From 92dd21dc9aee2dbf0c7d80b907c9179ed9dcf29d Mon Sep 17 00:00:00 2001 From: Gregory Rushton Date: Tue, 19 Sep 2023 13:21:03 -0400 Subject: [PATCH 1/3] [DUOS-2669][risk=no] Fix dataset selection bug (#2332) * rm the active check * add dac approval to the check --- src/pages/DatasetCatalog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/DatasetCatalog.js b/src/pages/DatasetCatalog.js index 2c99c12a2..ff8882790 100644 --- a/src/pages/DatasetCatalog.js +++ b/src/pages/DatasetCatalog.js @@ -25,7 +25,7 @@ const tableBody = { }; const canApplyForDataset = (dataset) => { - return dataset.active && !isNil(dataset.dacId); + return !isNil(dataset.dacId) && dataset.dacApproval; }; const extractDatasetProp = (propertyName, dataset) => { From 277f58d4dce150cf03902b48ec7a3f12870f613f Mon Sep 17 00:00:00 2001 From: Hamsini Malli Date: Tue, 19 Sep 2023 13:46:38 -0400 Subject: [PATCH 2/3] commented out code causing the error (#2331) --- scripts/compile-jsonschema.sh | 2 +- .../schemas/DataRegistrationV1Validation.js | 2177 ++++++++++++++++- 2 files changed, 2177 insertions(+), 2 deletions(-) diff --git a/scripts/compile-jsonschema.sh b/scripts/compile-jsonschema.sh index b12f791eb..f7ecfedf1 100755 --- a/scripts/compile-jsonschema.sh +++ b/scripts/compile-jsonschema.sh @@ -50,7 +50,7 @@ download_and_compile_schema() { curl -s -S -X 'GET' "$1/schemas/dataset-registration/v1" -H 'accept: application/json' -o ./src/assets/schemas/DataRegistrationV1.json # Generate the data submission schema validation code - ajv compile -s ./src/assets/schemas/DataRegistrationV1.json -o ./src/assets/schemas/DataRegistrationV1Validation.js --spec draft2019 -c ajv-formats --strict false --all-errors + ajv compile --code-lines -s ./src/assets/schemas/DataRegistrationV1.json -o ./src/assets/schemas/DataRegistrationV1Validation.js --spec draft2019 -c ajv-formats --strict false --all-errors # Prevent linting errors (minified file) prepend_text "/* eslint-disable */" ./src/assets/schemas/DataRegistrationV1Validation.js diff --git a/src/assets/schemas/DataRegistrationV1Validation.js b/src/assets/schemas/DataRegistrationV1Validation.js index fdb440832..a1dccf2dd 100644 --- a/src/assets/schemas/DataRegistrationV1Validation.js +++ b/src/assets/schemas/DataRegistrationV1Validation.js @@ -1 +1,2176 @@ -/* eslint-disable */ "use strict";module.exports = validate28;module.exports.default = validate28;const schema32 = {"$id":"https://consent.dsde-prod.broadinstitute.org/schemas/dataset-registration","$schema":"https://json-schema.org/draft/2019-09/schema","title":"Dataset Registration Schema","version":1,"type":"object","required":["studyName","studyDescription","dataTypes","dataSubmitterUserId","publicVisibility","nihAnvilUse","piName","consentGroups"],"allOf":[{"$comment":"require GSR explanation if the user selected yes","if":{"required":["controlledAccessRequiredForGenomicSummaryResultsGSR"],"properties":{"controlledAccessRequiredForGenomicSummaryResultsGSR":{"const":true}}},"then":{"required":["controlledAccessRequiredForGenomicSummaryResultsGSRRequiredExplanation"]}},{"$comment":"include dbGaP related fields if they have one","if":{"required":["nihAnvilUse"],"properties":{"nihAnvilUse":{"type":"string","enum":["I am NHGRI funded and I have a dbGaP PHS ID already"]}}},"then":{"$ref":"#/$defs/dbGaPInfo"}},{"$comment":"include NIH related fields if using AnVil","if":{"required":["nihAnvilUse"],"properties":{"nihAnvilUse":{"type":"string","enum":["I am NHGRI funded and I have a dbGaP PHS ID already","I am NHGRI funded and I do not have a dbGaP PHS ID","I am not NHGRI funded but I am seeking to submit data to AnVIL"]}}},"then":{"$ref":"#/$defs/nihAdministrativeInformation"}},{"$comment":"require alternative data sharing plan fields if the DS needs one","if":{"required":["alternativeDataSharingPlan"],"properties":{"alternativeDataSharingPlan":{"const":true}}},"then":{"required":["alternativeDataSharingPlanExplanation","alternativeDataSharingPlanReasons"],"properties":{"alternativeDataSharingPlanReasons":{"minItems":1}}}}],"properties":{"studyName":{"type":"string","label":"Study Name","description":"The study name","minLength":1},"studyType":{"type":"string","enum":["Observational","Interventional","Descriptive","Analytical","Prospective","Retrospective","Case report","Case series","Cross-sectional","Cohort study"],"label":"Study Type","description":"The study type"},"studyDescription":{"type":"string","label":"Study Description","description":"Description of the study","minLength":1},"dataTypes":{"type":"array","label":"Data Types","description":"All data types that study encompasses","items":{"type":"string"},"minItems":1},"phenotypeIndication":{"type":"string","label":"Phenotype/Indication Studied","description":"Phenotype/Indication Studied"},"species":{"type":"string","label":"Species","description":"Species"},"piName":{"type":"string","label":"Principal Investigator Name","description":"Principal Investigator Name","minLength":1},"dataSubmitterUserId":{"type":"integer","label":"Data Submitter","description":"The user creating the dataset submission"},"dataCustodianEmail":{"type":"array","label":"Data Custodian Email","description":"Data Custodian Email","items":{"type":"string","format":"email"}},"publicVisibility":{"type":"boolean","label":"Public Visibility","description":"Public Visibility of this study","prompt":"Please select if you would like your dataset to be publicly visible for the requesters to see and select for an access request"},"nihAnvilUse":{"type":"string","enum":["I am NHGRI funded and I have a dbGaP PHS ID already","I am NHGRI funded and I do not have a dbGaP PHS ID","I am not NHGRI funded but I am seeking to submit data to AnVIL","I am not NHGRI funded and do not plan to store data in AnVIL"],"description":"NIH Anvil Use"},"targetDeliveryDate":{"type":"string","format":"date","label":"Target Delivery Date","description":"Target Delivery Date"},"targetPublicReleaseDate":{"type":"string","format":"date","label":"Target Public Release Date","description":"Target Public Release Date"},"consentGroups":{"type":"array","minItems":1,"label":"Consent Groups","description":"Consent Groups","items":{"$ref":"#/$defs/consentGroup"}}},"$defs":{"fileTypeObject":{"type":"object","properties":{"fileType":{"type":"string","description":"File Type","enum":["Arrays","Genome","Exome","Survey","Phenotype"]},"functionalEquivalence":{"type":"string","description":"Functional Equivalence"}}},"dbGaPInfo":{"required":["dbGaPPhsID"],"properties":{"dbGaPPhsID":{"type":"string","label":"dbGaP phs ID","description":"dbGaP phs ID","minLength":1},"dbGaPStudyRegistrationName":{"type":"string","label":"dbGaP Study Registration Name","description":"dbGaP Study Registration Name"},"embargoReleaseDate":{"type":"string","format":"date","label":"Embargo Release Date","description":"Embargo Release Date"},"sequencingCenter":{"type":"string","label":"Sequencing Center","description":"Sequencing Center"}}},"nihAdministrativeInformation":{"required":["piInstitution","nihGrantContractNumber"],"properties":{"piInstitution":{"type":"integer","label":"Principal Investigator Institution","description":"Principal Investigator Institution"},"nihGrantContractNumber":{"type":"string","label":"NIH Grant or Contract Number","description":"NIH Grant or Contract Number","minLength":1},"nihICsSupportingStudy":{"type":"array","label":"NIH ICs Supporting the Study","description":"NIH ICs Supporting the Study","items":{"type":"string","enum":["NCI","NEI","NHLBI","NHGRI","NIA","NIAAA","NIAID","NIAMS","NIBIB","NICHD","NIDCD","NIDCR","NIDDK","NIDA","NIEHS","NIGMS","NIMH","NIMHD","NINDS","NINR","NLM","CC","CIT","CSR","FIC","NCATS","NCCIH"]}},"nihProgramOfficerName":{"type":"string","label":"NIH Program Officer Name","description":"NIH Program Officer Name"},"nihInstitutionCenterSubmission":{"type":"string","label":"NIH Institution/Center for Submission","description":"NIH Institution/Center for Submission","enum":["NCI","NEI","NHLBI","NHGRI","NIA","NIAAA","NIAID","NIAMS","NIBIB","NICHD","NIDCD","NIDCR","NIDDK","NIDA","NIEHS","NIGMS","NIMH","NIMHD","NINDS","NINR","NLM","CC","CIT","CSR","FIC","NCATS","NCCIH"]},"nihGenomicProgramAdministratorName":{"type":"string","label":"NIH Genomic Program Administrator Name","description":"NIH Genomic Program Administrator Name"},"multiCenterStudy":{"type":"boolean","label":"Is this a multi-center study?","description":"Is this a multi-center study?"},"collaboratingSites":{"type":"array","label":"What are the collaborating sites?","description":"What are the collaborating sites?","items":{"type":"string"}},"controlledAccessRequiredForGenomicSummaryResultsGSR":{"type":"boolean","label":"Is controlled access required for genomic summary results (GSR)?","description":"Is controlled access required for genomic summary results (GSR)?"},"controlledAccessRequiredForGenomicSummaryResultsGSRRequiredExplanation":{"type":"string","label":"If yes, explain why controlled access is required for GSR","description":"If yes, explain why controlled access is required for GSR","minLength":1},"alternativeDataSharingPlan":{"type":"boolean","label":"Are you requesting an Alternative Data Sharing Plan for samples that cannot be shared through a public repository or database?","description":"Are you requesting an Alternative Data Sharing Plan for samples that cannot be shared through a public repository or database?"},"alternativeDataSharingPlanReasons":{"type":"array","label":"Please mark the reasons for which you are requesting an Alternative Data Sharing Plan (check all that apply)","description":"Please mark the reasons for which you are requesting an Alternative Data Sharing Plan (check all that apply)","items":{"type":"string","enum":["Legal Restrictions","Informed consent processes are inadequate to support data for sharing for the following reasons:","The consent forms are unavailable or non-existent for samples collected after January 25, 2015","The consent process did not specifically address future use or broad data sharing for samples collected after January 25, 2015","The consent process inadequately addresses risks related to future use or broad data sharing for samples collected after January 25, 2015","The consent process specifically precludes future use or broad data sharing (including a statement that use of data will be limited to the original researchers)","Other informed consent limitations or concerns","Other"]}},"alternativeDataSharingPlanExplanation":{"type":"string","label":"Explanation of Request","description":"Explanation of Request"},"alternativeDataSharingPlanFileName":{"type":"string","label":"Upload your alternative sharing plan (file upload)","description":"Upload your alternative sharing plan (file upload)"},"alternativeDataSharingPlanDataSubmitted":{"type":"string","label":"Data will be submitted","description":"Upload your alternative sharing plan (file upload)","enum":["Within 3 months of the last data generated or last clinical visit","By batches over Study Timeline (e.g. based on clinical trial enrollment benchmarks)"]},"alternativeDataSharingPlanDataReleased":{"type":"boolean","label":"Data to be released will meet the timeframes specified in the NHGRI Guidance for Data Submission and Data Release","description":"Data to be released will meet the timeframes specified in the NHGRI Guidance for Data Submission and Data Release"},"alternativeDataSharingPlanTargetDeliveryDate":{"type":"string","format":"date","label":"Target Delivery Date","description":"Target Delivery Date"},"alternativeDataSharingPlanControlledOpenAccess":{"type":"string","label":"Does the data need to be managed under Controlled or Open Access?","description":"Does the data need to be managed under Controlled or Open Access?","enum":["Controlled Access","Open Access"]}}},"consentGroup":{"type":"object","required":["consentGroupName","fileTypes","numberOfParticipants"],"allOf":[{"if":{"properties":{"dataLocation":{"const":"Not Determined"}}},"then":{},"else":{"required":["url"]}},{"$comment":"if openAccess is false OR not present, then require dac id & add secondary consent fields","if":{"properties":{"openAccess":{"const":false}}},"then":{"required":["dataAccessCommitteeId"],"properties":{"nmds":{"type":"boolean","label":"No Methods Development or validation studies (NMDS)","description":"No Methods Development or validation studies (NMDS)"},"gso":{"type":"boolean","label":"Genetic studies only (GSO)","description":"Genetic studies only (GSO)"},"pub":{"type":"boolean","label":"Publication Required (PUB)","description":"Publication Required (PUB)"},"col":{"type":"boolean","label":"Collaboration Required (COL)","description":"Collaboration Required (COL)"},"irb":{"type":"boolean","label":"Ethics Approval Required (IRB)","description":"Ethics Approval Required (IRB)"},"gs":{"type":"string","label":"Geographic Restriction (GS-)","description":"Geographic Restriction (GS-)"},"mor":{"type":"boolean","label":"Publication Moratorium (MOR)","description":"Publication Moratorium (MOR)"},"morDate":{"type":"string","format":"date","label":"Publication Moratorium Date (MOR)","description":"Publication Moratorium Date (MOR)"},"npu":{"type":"boolean","label":"Non-profit Use Only (NPU)","description":"Non-profit Use Only (NPU)"},"otherSecondary":{"type":"string","label":"Other","description":"Other"},"dataAccessCommitteeId":{"type":"integer","label":"Please select which DAC should govern requests for this dataset","description":"Data Access Committee ID"}}}},{"$comment":"ensure one (and only one) primary consent is selected","oneOf":[{"properties":{"openAccess":{"const":true}},"required":["openAccess"]},{"properties":{"generalResearchUse":{"const":true}},"required":["generalResearchUse"]},{"properties":{"hmb":{"const":true}},"required":["hmb"]},{"properties":{"poa":{"const":true}},"required":["poa"]},{"properties":{"diseaseSpecificUse":{"minItems":1}},"required":["diseaseSpecificUse"]},{"properties":{"otherPrimary":{"minLength":1}},"required":["otherPrimary"]}]}],"properties":{"datasetId":{"type":"integer","description":"Dataset Id"},"consentGroupName":{"type":"string","label":"Consent Group Name","description":"Consent Group Name","minLength":1},"openAccess":{"type":"boolean","label":"No Restrictions","description":"No Restrictions"},"generalResearchUse":{"type":"boolean","label":"General Research Use","description":"General Research Use"},"hmb":{"type":"boolean","label":"Health/Medical/Biomedical Research Use","description":"Health/Medical/Biomedical Research Use"},"diseaseSpecificUse":{"type":"array","label":"Disease-Specific Research Use","description":"Disease-Specific Research Use","items":{"type":"string"}},"poa":{"type":"boolean","label":"Populations, Origins, Ancestry Use","description":"Populations, Origins, Ancestry Use"},"otherPrimary":{"type":"string","label":"Other","description":"Other"},"dataLocation":{"type":"string","enum":["AnVIL Workspace","Terra Workspace","TDR Location","Not Determined"],"label":"Please provide the location of your data resource for this consent group","description":"Data Location"},"url":{"type":"string","format":"uri","label":"Free text field for entering URL of data","description":"Free text field for entering URL of data","minLength":1},"numberOfParticipants":{"type":"integer","description":"# of Participants"},"fileTypes":{"type":"array","minItems":1,"items":{"$ref":"#/$defs/fileTypeObject"},"description":"List of File Types"}}}}};const schema33 = {"required":["dbGaPPhsID"],"properties":{"dbGaPPhsID":{"type":"string","label":"dbGaP phs ID","description":"dbGaP phs ID","minLength":1},"dbGaPStudyRegistrationName":{"type":"string","label":"dbGaP Study Registration Name","description":"dbGaP Study Registration Name"},"embargoReleaseDate":{"type":"string","format":"date","label":"Embargo Release Date","description":"Embargo Release Date"},"sequencingCenter":{"type":"string","label":"Sequencing Center","description":"Sequencing Center"}}};const schema34 = {"required":["piInstitution","nihGrantContractNumber"],"properties":{"piInstitution":{"type":"integer","label":"Principal Investigator Institution","description":"Principal Investigator Institution"},"nihGrantContractNumber":{"type":"string","label":"NIH Grant or Contract Number","description":"NIH Grant or Contract Number","minLength":1},"nihICsSupportingStudy":{"type":"array","label":"NIH ICs Supporting the Study","description":"NIH ICs Supporting the Study","items":{"type":"string","enum":["NCI","NEI","NHLBI","NHGRI","NIA","NIAAA","NIAID","NIAMS","NIBIB","NICHD","NIDCD","NIDCR","NIDDK","NIDA","NIEHS","NIGMS","NIMH","NIMHD","NINDS","NINR","NLM","CC","CIT","CSR","FIC","NCATS","NCCIH"]}},"nihProgramOfficerName":{"type":"string","label":"NIH Program Officer Name","description":"NIH Program Officer Name"},"nihInstitutionCenterSubmission":{"type":"string","label":"NIH Institution/Center for Submission","description":"NIH Institution/Center for Submission","enum":["NCI","NEI","NHLBI","NHGRI","NIA","NIAAA","NIAID","NIAMS","NIBIB","NICHD","NIDCD","NIDCR","NIDDK","NIDA","NIEHS","NIGMS","NIMH","NIMHD","NINDS","NINR","NLM","CC","CIT","CSR","FIC","NCATS","NCCIH"]},"nihGenomicProgramAdministratorName":{"type":"string","label":"NIH Genomic Program Administrator Name","description":"NIH Genomic Program Administrator Name"},"multiCenterStudy":{"type":"boolean","label":"Is this a multi-center study?","description":"Is this a multi-center study?"},"collaboratingSites":{"type":"array","label":"What are the collaborating sites?","description":"What are the collaborating sites?","items":{"type":"string"}},"controlledAccessRequiredForGenomicSummaryResultsGSR":{"type":"boolean","label":"Is controlled access required for genomic summary results (GSR)?","description":"Is controlled access required for genomic summary results (GSR)?"},"controlledAccessRequiredForGenomicSummaryResultsGSRRequiredExplanation":{"type":"string","label":"If yes, explain why controlled access is required for GSR","description":"If yes, explain why controlled access is required for GSR","minLength":1},"alternativeDataSharingPlan":{"type":"boolean","label":"Are you requesting an Alternative Data Sharing Plan for samples that cannot be shared through a public repository or database?","description":"Are you requesting an Alternative Data Sharing Plan for samples that cannot be shared through a public repository or database?"},"alternativeDataSharingPlanReasons":{"type":"array","label":"Please mark the reasons for which you are requesting an Alternative Data Sharing Plan (check all that apply)","description":"Please mark the reasons for which you are requesting an Alternative Data Sharing Plan (check all that apply)","items":{"type":"string","enum":["Legal Restrictions","Informed consent processes are inadequate to support data for sharing for the following reasons:","The consent forms are unavailable or non-existent for samples collected after January 25, 2015","The consent process did not specifically address future use or broad data sharing for samples collected after January 25, 2015","The consent process inadequately addresses risks related to future use or broad data sharing for samples collected after January 25, 2015","The consent process specifically precludes future use or broad data sharing (including a statement that use of data will be limited to the original researchers)","Other informed consent limitations or concerns","Other"]}},"alternativeDataSharingPlanExplanation":{"type":"string","label":"Explanation of Request","description":"Explanation of Request"},"alternativeDataSharingPlanFileName":{"type":"string","label":"Upload your alternative sharing plan (file upload)","description":"Upload your alternative sharing plan (file upload)"},"alternativeDataSharingPlanDataSubmitted":{"type":"string","label":"Data will be submitted","description":"Upload your alternative sharing plan (file upload)","enum":["Within 3 months of the last data generated or last clinical visit","By batches over Study Timeline (e.g. based on clinical trial enrollment benchmarks)"]},"alternativeDataSharingPlanDataReleased":{"type":"boolean","label":"Data to be released will meet the timeframes specified in the NHGRI Guidance for Data Submission and Data Release","description":"Data to be released will meet the timeframes specified in the NHGRI Guidance for Data Submission and Data Release"},"alternativeDataSharingPlanTargetDeliveryDate":{"type":"string","format":"date","label":"Target Delivery Date","description":"Target Delivery Date"},"alternativeDataSharingPlanControlledOpenAccess":{"type":"string","label":"Does the data need to be managed under Controlled or Open Access?","description":"Does the data need to be managed under Controlled or Open Access?","enum":["Controlled Access","Open Access"]}}};const func3 = require("ajv/dist/runtime/ucs2length").default;const formats0 = {"_items":["require(\"ajv-formats/dist/formats\").",{"str":"fullFormats"},""]}.date;const formats4 = /^[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i;const schema35 = {"type":"object","required":["consentGroupName","fileTypes","numberOfParticipants"],"allOf":[{"if":{"properties":{"dataLocation":{"const":"Not Determined"}}},"then":{},"else":{"required":["url"]}},{"$comment":"if openAccess is false OR not present, then require dac id & add secondary consent fields","if":{"properties":{"openAccess":{"const":false}}},"then":{"required":["dataAccessCommitteeId"],"properties":{"nmds":{"type":"boolean","label":"No Methods Development or validation studies (NMDS)","description":"No Methods Development or validation studies (NMDS)"},"gso":{"type":"boolean","label":"Genetic studies only (GSO)","description":"Genetic studies only (GSO)"},"pub":{"type":"boolean","label":"Publication Required (PUB)","description":"Publication Required (PUB)"},"col":{"type":"boolean","label":"Collaboration Required (COL)","description":"Collaboration Required (COL)"},"irb":{"type":"boolean","label":"Ethics Approval Required (IRB)","description":"Ethics Approval Required (IRB)"},"gs":{"type":"string","label":"Geographic Restriction (GS-)","description":"Geographic Restriction (GS-)"},"mor":{"type":"boolean","label":"Publication Moratorium (MOR)","description":"Publication Moratorium (MOR)"},"morDate":{"type":"string","format":"date","label":"Publication Moratorium Date (MOR)","description":"Publication Moratorium Date (MOR)"},"npu":{"type":"boolean","label":"Non-profit Use Only (NPU)","description":"Non-profit Use Only (NPU)"},"otherSecondary":{"type":"string","label":"Other","description":"Other"},"dataAccessCommitteeId":{"type":"integer","label":"Please select which DAC should govern requests for this dataset","description":"Data Access Committee ID"}}}},{"$comment":"ensure one (and only one) primary consent is selected","oneOf":[{"properties":{"openAccess":{"const":true}},"required":["openAccess"]},{"properties":{"generalResearchUse":{"const":true}},"required":["generalResearchUse"]},{"properties":{"hmb":{"const":true}},"required":["hmb"]},{"properties":{"poa":{"const":true}},"required":["poa"]},{"properties":{"diseaseSpecificUse":{"minItems":1}},"required":["diseaseSpecificUse"]},{"properties":{"otherPrimary":{"minLength":1}},"required":["otherPrimary"]}]}],"properties":{"datasetId":{"type":"integer","description":"Dataset Id"},"consentGroupName":{"type":"string","label":"Consent Group Name","description":"Consent Group Name","minLength":1},"openAccess":{"type":"boolean","label":"No Restrictions","description":"No Restrictions"},"generalResearchUse":{"type":"boolean","label":"General Research Use","description":"General Research Use"},"hmb":{"type":"boolean","label":"Health/Medical/Biomedical Research Use","description":"Health/Medical/Biomedical Research Use"},"diseaseSpecificUse":{"type":"array","label":"Disease-Specific Research Use","description":"Disease-Specific Research Use","items":{"type":"string"}},"poa":{"type":"boolean","label":"Populations, Origins, Ancestry Use","description":"Populations, Origins, Ancestry Use"},"otherPrimary":{"type":"string","label":"Other","description":"Other"},"dataLocation":{"type":"string","enum":["AnVIL Workspace","Terra Workspace","TDR Location","Not Determined"],"label":"Please provide the location of your data resource for this consent group","description":"Data Location"},"url":{"type":"string","format":"uri","label":"Free text field for entering URL of data","description":"Free text field for entering URL of data","minLength":1},"numberOfParticipants":{"type":"integer","description":"# of Participants"},"fileTypes":{"type":"array","minItems":1,"items":{"$ref":"#/$defs/fileTypeObject"},"description":"List of File Types"}}};const schema36 = {"type":"object","properties":{"fileType":{"type":"string","description":"File Type","enum":["Arrays","Genome","Exome","Survey","Phenotype"]},"functionalEquivalence":{"type":"string","description":"Functional Equivalence"}}};const formats12 = {"_items":["require(\"ajv-formats/dist/formats\").",{"str":"fullFormats"},""]}.uri;function validate29(data, {instancePath="", parentData, parentDataProperty, rootData=data, dynamicAnchors={}}={}){let vErrors = null;let errors = 0;const evaluated0 = validate29.evaluated;if(evaluated0.dynamicProps){evaluated0.props = undefined;}if(evaluated0.dynamicItems){evaluated0.items = undefined;}const _errs2 = errors;let valid1 = true;const _errs3 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.dataLocation !== undefined){if("Not Determined" !== data.dataLocation){const err0 = {};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}}}var _valid0 = _errs3 === errors;errors = _errs2;if(vErrors !== null){if(_errs2){vErrors.length = _errs2;}else {vErrors = null;}}if(!_valid0){const _errs5 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.url === undefined){const err1 = {instancePath,schemaPath:"#/allOf/0/else/required",keyword:"required",params:{missingProperty: "url"},message:"must have required property '"+"url"+"'"};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}var _valid0 = _errs5 === errors;valid1 = _valid0;}if(!valid1){const err2 = {instancePath,schemaPath:"#/allOf/0/if",keyword:"if",params:{failingKeyword: "else"},message:"must match \"else\" schema"};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}const _errs8 = errors;let valid3 = true;const _errs9 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.openAccess !== undefined){if(false !== data.openAccess){const err3 = {};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}}var _valid1 = _errs9 === errors;errors = _errs8;if(vErrors !== null){if(_errs8){vErrors.length = _errs8;}else {vErrors = null;}}if(_valid1){const _errs11 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.dataAccessCommitteeId === undefined){const err4 = {instancePath,schemaPath:"#/allOf/1/then/required",keyword:"required",params:{missingProperty: "dataAccessCommitteeId"},message:"must have required property '"+"dataAccessCommitteeId"+"'"};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}if(data.nmds !== undefined){if(typeof data.nmds !== "boolean"){const err5 = {instancePath:instancePath+"/nmds",schemaPath:"#/allOf/1/then/properties/nmds/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.gso !== undefined){if(typeof data.gso !== "boolean"){const err6 = {instancePath:instancePath+"/gso",schemaPath:"#/allOf/1/then/properties/gso/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.pub !== undefined){if(typeof data.pub !== "boolean"){const err7 = {instancePath:instancePath+"/pub",schemaPath:"#/allOf/1/then/properties/pub/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data.col !== undefined){if(typeof data.col !== "boolean"){const err8 = {instancePath:instancePath+"/col",schemaPath:"#/allOf/1/then/properties/col/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data.irb !== undefined){if(typeof data.irb !== "boolean"){const err9 = {instancePath:instancePath+"/irb",schemaPath:"#/allOf/1/then/properties/irb/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}if(data.gs !== undefined){if(typeof data.gs !== "string"){const err10 = {instancePath:instancePath+"/gs",schemaPath:"#/allOf/1/then/properties/gs/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.mor !== undefined){if(typeof data.mor !== "boolean"){const err11 = {instancePath:instancePath+"/mor",schemaPath:"#/allOf/1/then/properties/mor/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data.morDate !== undefined){let data9 = data.morDate;if(typeof data9 === "string"){if(!(formats0.validate(data9))){const err12 = {instancePath:instancePath+"/morDate",schemaPath:"#/allOf/1/then/properties/morDate/format",keyword:"format",params:{format: "date"},message:"must match format \""+"date"+"\""};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}else {const err13 = {instancePath:instancePath+"/morDate",schemaPath:"#/allOf/1/then/properties/morDate/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}if(data.npu !== undefined){if(typeof data.npu !== "boolean"){const err14 = {instancePath:instancePath+"/npu",schemaPath:"#/allOf/1/then/properties/npu/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.otherSecondary !== undefined){if(typeof data.otherSecondary !== "string"){const err15 = {instancePath:instancePath+"/otherSecondary",schemaPath:"#/allOf/1/then/properties/otherSecondary/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}}if(data.dataAccessCommitteeId !== undefined){let data12 = data.dataAccessCommitteeId;if(!((typeof data12 == "number") && (!(data12 % 1) && !isNaN(data12)))){const err16 = {instancePath:instancePath+"/dataAccessCommitteeId",schemaPath:"#/allOf/1/then/properties/dataAccessCommitteeId/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}var _valid1 = _errs11 === errors;valid3 = _valid1;if(valid3){var props0 = {};props0.nmds = true;props0.gso = true;props0.pub = true;props0.col = true;props0.irb = true;props0.gs = true;props0.mor = true;props0.morDate = true;props0.npu = true;props0.otherSecondary = true;props0.dataAccessCommitteeId = true;props0.openAccess = true;}}if(!valid3){const err17 = {instancePath,schemaPath:"#/allOf/1/if",keyword:"if",params:{failingKeyword: "then"},message:"must match \"then\" schema"};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}if(props0 !== true){props0 = props0 || {};props0.dataLocation = true;}const _errs36 = errors;let valid6 = false;let passing0 = null;const _errs37 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.openAccess === undefined){const err18 = {instancePath,schemaPath:"#/allOf/2/oneOf/0/required",keyword:"required",params:{missingProperty: "openAccess"},message:"must have required property '"+"openAccess"+"'"};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}if(data.openAccess !== undefined){if(true !== data.openAccess){const err19 = {instancePath:instancePath+"/openAccess",schemaPath:"#/allOf/2/oneOf/0/properties/openAccess/const",keyword:"const",params:{allowedValue: true},message:"must be equal to constant"};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}}}var _valid2 = _errs37 === errors;if(_valid2){valid6 = true;passing0 = 0;var props1 = {};props1.openAccess = true;}const _errs39 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.generalResearchUse === undefined){const err20 = {instancePath,schemaPath:"#/allOf/2/oneOf/1/required",keyword:"required",params:{missingProperty: "generalResearchUse"},message:"must have required property '"+"generalResearchUse"+"'"};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}if(data.generalResearchUse !== undefined){if(true !== data.generalResearchUse){const err21 = {instancePath:instancePath+"/generalResearchUse",schemaPath:"#/allOf/2/oneOf/1/properties/generalResearchUse/const",keyword:"const",params:{allowedValue: true},message:"must be equal to constant"};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}}}var _valid2 = _errs39 === errors;if(_valid2 && valid6){valid6 = false;passing0 = [passing0, 1];}else {if(_valid2){valid6 = true;passing0 = 1;if(props1 !== true){props1 = props1 || {};props1.generalResearchUse = true;}}const _errs41 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.hmb === undefined){const err22 = {instancePath,schemaPath:"#/allOf/2/oneOf/2/required",keyword:"required",params:{missingProperty: "hmb"},message:"must have required property '"+"hmb"+"'"};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}if(data.hmb !== undefined){if(true !== data.hmb){const err23 = {instancePath:instancePath+"/hmb",schemaPath:"#/allOf/2/oneOf/2/properties/hmb/const",keyword:"const",params:{allowedValue: true},message:"must be equal to constant"};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}}var _valid2 = _errs41 === errors;if(_valid2 && valid6){valid6 = false;passing0 = [passing0, 2];}else {if(_valid2){valid6 = true;passing0 = 2;if(props1 !== true){props1 = props1 || {};props1.hmb = true;}}const _errs43 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.poa === undefined){const err24 = {instancePath,schemaPath:"#/allOf/2/oneOf/3/required",keyword:"required",params:{missingProperty: "poa"},message:"must have required property '"+"poa"+"'"};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}if(data.poa !== undefined){if(true !== data.poa){const err25 = {instancePath:instancePath+"/poa",schemaPath:"#/allOf/2/oneOf/3/properties/poa/const",keyword:"const",params:{allowedValue: true},message:"must be equal to constant"};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;}}}var _valid2 = _errs43 === errors;if(_valid2 && valid6){valid6 = false;passing0 = [passing0, 3];}else {if(_valid2){valid6 = true;passing0 = 3;if(props1 !== true){props1 = props1 || {};props1.poa = true;}}const _errs45 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.diseaseSpecificUse === undefined){const err26 = {instancePath,schemaPath:"#/allOf/2/oneOf/4/required",keyword:"required",params:{missingProperty: "diseaseSpecificUse"},message:"must have required property '"+"diseaseSpecificUse"+"'"};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}if(data.diseaseSpecificUse !== undefined){let data17 = data.diseaseSpecificUse;if(Array.isArray(data17)){if(data17.length < 1){const err27 = {instancePath:instancePath+"/diseaseSpecificUse",schemaPath:"#/allOf/2/oneOf/4/properties/diseaseSpecificUse/minItems",keyword:"minItems",params:{limit: 1},message:"must NOT have fewer than 1 items"};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}}}}var _valid2 = _errs45 === errors;if(_valid2 && valid6){valid6 = false;passing0 = [passing0, 4];}else {if(_valid2){valid6 = true;passing0 = 4;if(props1 !== true){props1 = props1 || {};props1.diseaseSpecificUse = true;}}const _errs47 = errors;if(data && typeof data == "object" && !Array.isArray(data)){if(data.otherPrimary === undefined){const err28 = {instancePath,schemaPath:"#/allOf/2/oneOf/5/required",keyword:"required",params:{missingProperty: "otherPrimary"},message:"must have required property '"+"otherPrimary"+"'"};if(vErrors === null){vErrors = [err28];}else {vErrors.push(err28);}errors++;}if(data.otherPrimary !== undefined){let data18 = data.otherPrimary;if(typeof data18 === "string"){if(func3(data18) < 1){const err29 = {instancePath:instancePath+"/otherPrimary",schemaPath:"#/allOf/2/oneOf/5/properties/otherPrimary/minLength",keyword:"minLength",params:{limit: 1},message:"must NOT have fewer than 1 characters"};if(vErrors === null){vErrors = [err29];}else {vErrors.push(err29);}errors++;}}}}var _valid2 = _errs47 === errors;if(_valid2 && valid6){valid6 = false;passing0 = [passing0, 5];}else {if(_valid2){valid6 = true;passing0 = 5;if(props1 !== true){props1 = props1 || {};props1.otherPrimary = true;}}}}}}}if(!valid6){const err30 = {instancePath,schemaPath:"#/allOf/2/oneOf",keyword:"oneOf",params:{passingSchemas: passing0},message:"must match exactly one schema in oneOf"};if(vErrors === null){vErrors = [err30];}else {vErrors.push(err30);}errors++;}else {errors = _errs36;if(vErrors !== null){if(_errs36){vErrors.length = _errs36;}else {vErrors = null;}}}if(props0 !== true && props1 !== undefined){if(props1 === true){props0 = true;}else {props0 = props0 || {};Object.assign(props0, props1);}}if(data && typeof data == "object" && !Array.isArray(data)){if(data.consentGroupName === undefined){const err31 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "consentGroupName"},message:"must have required property '"+"consentGroupName"+"'"};if(vErrors === null){vErrors = [err31];}else {vErrors.push(err31);}errors++;}if(data.fileTypes === undefined){const err32 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "fileTypes"},message:"must have required property '"+"fileTypes"+"'"};if(vErrors === null){vErrors = [err32];}else {vErrors.push(err32);}errors++;}if(data.numberOfParticipants === undefined){const err33 = {instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: "numberOfParticipants"},message:"must have required property '"+"numberOfParticipants"+"'"};if(vErrors === null){vErrors = [err33];}else {vErrors.push(err33);}errors++;}if(props0 !== true){props0 = props0 || {};props0.datasetId = true;props0.consentGroupName = true;props0.openAccess = true;props0.generalResearchUse = true;props0.hmb = true;props0.diseaseSpecificUse = true;props0.poa = true;props0.otherPrimary = true;props0.dataLocation = true;props0.url = true;props0.numberOfParticipants = true;props0.fileTypes = true;}if(data.datasetId !== undefined){let data19 = data.datasetId;if(!((typeof data19 == "number") && (!(data19 % 1) && !isNaN(data19)))){const err34 = {instancePath:instancePath+"/datasetId",schemaPath:"#/properties/datasetId/type",keyword:"type",params:{type: "integer"},message:"must be integer"};if(vErrors === null){vErrors = [err34];}else {vErrors.push(err34);}errors++;}}if(data.consentGroupName !== undefined){let data20 = data.consentGroupName;if(typeof data20 === "string"){if(func3(data20) < 1){const err35 = {instancePath:instancePath+"/consentGroupName",schemaPath:"#/properties/consentGroupName/minLength",keyword:"minLength",params:{limit: 1},message:"must NOT have fewer than 1 characters"};if(vErrors === null){vErrors = [err35];}else {vErrors.push(err35);}errors++;}}else {const err36 = {instancePath:instancePath+"/consentGroupName",schemaPath:"#/properties/consentGroupName/type",keyword:"type",params:{type: "string"},message:"must be string"};if(vErrors === null){vErrors = [err36];}else {vErrors.push(err36);}errors++;}}if(data.openAccess !== undefined){if(typeof data.openAccess !== "boolean"){const err37 = {instancePath:instancePath+"/openAccess",schemaPath:"#/properties/openAccess/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err37];}else {vErrors.push(err37);}errors++;}}if(data.generalResearchUse !== undefined){if(typeof data.generalResearchUse !== "boolean"){const err38 = {instancePath:instancePath+"/generalResearchUse",schemaPath:"#/properties/generalResearchUse/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err38];}else {vErrors.push(err38);}errors++;}}if(data.hmb !== undefined){if(typeof data.hmb !== "boolean"){const err39 = {instancePath:instancePath+"/hmb",schemaPath:"#/properties/hmb/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"};if(vErrors === null){vErrors = [err39];}else {vErrors.push(err39);}errors++;}}if(data.diseaseSpecificUse !== undefined){let data24 = data.diseaseSpecificUse;if(Array.isArray(data24)){const len0 = data24.length;for(let i0=0; i0 Date: Tue, 19 Sep 2023 14:56:08 -0400 Subject: [PATCH 3/3] [DUOS-2641][risk=no] Submitted Datasets Subtab (#2322) * data submitter sub nav in researcher console --- src/Routes.js | 4 +- src/components/DuosHeader.js | 17 +- .../sortable_table/SortableTable.js | 20 +-- src/libs/utils.js | 142 +++++++++++------ .../researcher_console/DatasetSubmissions.jsx | 149 ++++++++++++++++++ .../DatasetSubmissionsTable.jsx | 123 +++++++++++++++ .../DatasetTerms.module.css | 28 ++++ .../ResearcherConsole.js | 67 ++++---- 8 files changed, 449 insertions(+), 101 deletions(-) create mode 100644 src/pages/researcher_console/DatasetSubmissions.jsx create mode 100644 src/pages/researcher_console/DatasetSubmissionsTable.jsx create mode 100644 src/pages/researcher_console/DatasetTerms.module.css rename src/pages/{ => researcher_console}/ResearcherConsole.js (71%) diff --git a/src/Routes.js b/src/Routes.js index 60b7a8490..6d3b6eaf1 100644 --- a/src/Routes.js +++ b/src/Routes.js @@ -13,7 +13,7 @@ import Home from './pages/Home'; import NotFound from './pages/NotFound'; import NIHICWebform from './pages/NIHicWebform'; import PrivacyPolicy from './pages/PrivacyPolicy'; -import ResearcherConsole from './pages/ResearcherConsole'; +import ResearcherConsole from './pages/researcher_console/ResearcherConsole'; import UserProfile from './pages/user_profile/UserProfile'; import RequestRole from './pages/user_profile/RequestRole'; import SigningOfficialResearchers from './pages/signing_official_console/SigningOfficialResearchers'; @@ -33,6 +33,7 @@ import AdminManageDarCollections from './pages/AdminManageDarCollections'; import {AdminEditUser} from './pages/AdminEditUser'; import ChairConsole from './pages/ChairConsole'; import MemberConsole from './pages/MemberConsole'; +import DatasetSubmissions from './pages/researcher_console/DatasetSubmissions'; import TermsOfService from './pages/TermsOfService'; import TermsOfServiceAcceptance from './pages/TermsOfServiceAcceptance'; import {HealthCheck} from './pages/HealthCheck'; @@ -87,6 +88,7 @@ const Routes = (props) => ( {checkEnv(envGroups.NON_STAGING) && } + diff --git a/src/components/DuosHeader.js b/src/components/DuosHeader.js index f9d0fa87e..cb3c73eb0 100644 --- a/src/components/DuosHeader.js +++ b/src/components/DuosHeader.js @@ -125,22 +125,14 @@ export const headerTabsConfig = [ ], isRendered: (user) => user.isMember }, - { - label: 'DS Console', - link: '/data_submission_form', - search: 'data_submission_form', - children: [ - { label: 'Datasets', link: '/data_submission_form' } - ], - isRendered: (user) => user.isDataSubmitter - }, { label: 'Researcher Console', link: '/dataset_catalog', search: 'dataset_catalog', children: [ { label: 'Data Catalog', link: '/dataset_catalog' }, - { label: 'DAR Requests', link: '/researcher_console' } + { label: 'DAR Requests', link: '/researcher_console' }, + { label: 'Submitted Datasets', link: '/dataset_submissions', isRenderedForUser: (user) => user?.isDataSubmitter } ], isRendered: (user) => user.isResearcher && !isOnlySigningOfficial(user) } @@ -321,7 +313,10 @@ const NavigationTabsComponent = (props) => { const isRendered = (!isFunction(tab.isRendered) || isNil(tab.isRendered())) ? true : tab.isRendered(); - return isRendered ? h(Tab, { + const isRenderedForUser = (!isFunction(tab.isRenderedForUser) || isNil(tab.isRenderedForUser(currentUser))) ? + true : + tab.isRenderedForUser(currentUser); + return (isRendered && isRenderedForUser) ? h(Tab, { key: `${tab.link}_${tabIndex}`, label: tab.label, style: selectedSubTab === tabIndex ? styles.subTabActive : styles.subTab, diff --git a/src/components/sortable_table/SortableTable.js b/src/components/sortable_table/SortableTable.js index e3792d8b2..f68ba6316 100644 --- a/src/components/sortable_table/SortableTable.js +++ b/src/components/sortable_table/SortableTable.js @@ -39,7 +39,7 @@ Step 3: Pass both arrays into the headCells and rows props */ -import React from 'react'; +import React, {useState, useMemo} from 'react'; import Box from '@mui/material/Box'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; @@ -84,14 +84,16 @@ export default function SortableTable(props) { const { rows, - headCells + headCells, + defaultSort = 'darCode', + cellAlignment = 'center' } = props; - const [order, setOrder] = React.useState('asc'); - const [orderBy, setOrderBy] = React.useState('darCode'); - const [selected, setSelected] = React.useState([]); - const [page, setPage] = React.useState(0); - const [rowsPerPage, setRowsPerPage] = React.useState(10); + const [order, setOrder] = useState('asc'); + const [orderBy, setOrderBy] = useState(defaultSort); + const [selected, setSelected] = useState([]); + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(10); const handleRequestSort = (event, property) => { const isAsc = orderBy === property && order === 'asc'; @@ -135,7 +137,7 @@ export default function SortableTable(props) { const emptyRows = page > 0 ? Math.max(0, (1 + page) * rowsPerPage - rows.length) : 0; - const visibleRows = React.useMemo( + const visibleRows = useMemo( () => stableSort(rows, getComparator(order, orderBy)).slice( page * rowsPerPage, @@ -187,7 +189,7 @@ export default function SortableTable(props) { id={labelId} scope='row' padding='none' - align='center'> + align={cellAlignment}> {row[category]} ))} diff --git a/src/libs/utils.js b/src/libs/utils.js index a8815583f..ad566635c 100644 --- a/src/libs/utils.js +++ b/src/libs/utils.js @@ -1,11 +1,11 @@ import Noty from 'noty'; import 'noty/lib/noty.css'; import 'noty/lib/themes/bootstrap-v3.css'; -import {map as lodashMap, forEach as lodashForEach, isArray} from 'lodash'; -import { DAR } from './ajax'; -import {Theme } from './theme'; -import { each, flatten, flow, forEach as lodashFPForEach, get, getOr, uniq, find, first, map, isEmpty, filter, cloneDeep, isNil, toLower, includes, every, capitalize } from 'lodash/fp'; -import { headerTabsConfig } from '../components/DuosHeader'; +import {forEach as lodashForEach, isArray, map as lodashMap} from 'lodash'; +import {DAR} from './ajax'; +import {Theme} from './theme'; +import {capitalize, cloneDeep, concat, each, every, filter, find, first, flatten, flow, forEach as lodashFPForEach, get, getOr, includes, isEmpty, isNil, join, map, toLower, uniq} from 'lodash/fp'; +import {headerTabsConfig} from '../components/DuosHeader'; export const UserProperties = { SUGGESTED_SIGNING_OFFICIAL: 'suggestedSigningOfficial', @@ -16,7 +16,7 @@ export const UserProperties = { ///////DAR Collection Utils/////////////////////////////////////////////////////////////////////////////////// export const isCollectionCanceled = (collection) => { - const { dars } = collection; + const {dars} = collection; return every((dar) => toLower(dar.data.status) === 'canceled')(dars); }; @@ -28,15 +28,15 @@ export const darCollectionUtils = { determineCollectionStatus: (collection, relevantDatasets) => { const electionStatusCount = {}; let output; - if(!isEmpty(collection.dars)) { + if (!isEmpty(collection.dars)) { const targetElections = flow([ map((dar) => { - const { elections } = dar; + const {elections} = dar; //election is empty => no elections made for dar //need to figure out if dar is relevant, can obtain datasetId from dar.data //see if its relevant, if it is, add 1 to submitted on hash //return empty array at the end - if(isEmpty(elections)) { + if (isEmpty(elections)) { // Dataset IDs should be on the DAR, but if not, pull from the dar.data const datasetIds = isNil(dar.datasetIds) ? dar.data.datasetIds : dar.datasetIds; lodashFPForEach((datasetId) => { @@ -53,7 +53,7 @@ export const darCollectionUtils = { //only Data Access elections impact the status of the collection //NOTE: Admin does not have relevantIds, DAC roles do const electionArr = filter(election => toLower(election.electionType) === 'dataaccess')(Object.values(elections)); - if(isNil(relevantDatasets)) { + if (isNil(relevantDatasets)) { return electionArr; } else { const relevantIds = map(dataset => dataset.dataSetId)(relevantDatasets); @@ -64,10 +64,10 @@ export const darCollectionUtils = { flatten ])(collection.dars); - if(isNil(relevantDatasets)) { + if (isNil(relevantDatasets)) { each(election => { const {status} = election; - if(isNil(electionStatusCount[status])) { + if (isNil(electionStatusCount[status])) { electionStatusCount[status] = 0; } electionStatusCount[status]++; @@ -85,7 +85,7 @@ export const darCollectionUtils = { ///////DAR Collection Utils END///////////////////////////////////////////////////////////////////////////////// export const goToPage = (value, pageCount, setCurrentPage) => { - if(value >= 1 && value <= pageCount) { + if (value >= 1 && value <= pageCount) { setCurrentPage(value); } }; @@ -93,7 +93,7 @@ export const goToPage = (value, pageCount, setCurrentPage) => { export const findPropertyValue = (propName, researcher) => { const prop = isNil(researcher.researcherProperties) ? null - : find({ propertyKey: propName })(researcher.researcherProperties); + : find({propertyKey: propName})(researcher.researcherProperties); return isNil(prop) ? '' : prop.propertyValue; }; @@ -118,7 +118,7 @@ export const applyHoverEffects = (e, style) => { //currently, dars contain a list of datasets (any length) and a list of length 1 of a datasetId //go through the list of datasets and get the name of the dataset whose id is in the datasetId list export const getNameOfDatasetForThisDAR = (datasets, datasetId) => { - const data = !isNil(datasetId) && !isEmpty(datasetId) ? find({'value' : first(datasetId).toString()})(datasets) : null; + const data = !isNil(datasetId) && !isEmpty(datasetId) ? find({'value': first(datasetId).toString()})(datasets) : null; return isNil(data) ? '- -' : getDatasetNames([data]); }; @@ -127,7 +127,9 @@ export const formatDate = (dateval) => { return '---'; } - if(toLower(dateval) === 'unsubmitted') {return dateval;} + if (toLower(dateval) === 'unsubmitted') { + return dateval; + } let dateFormat = new Date(dateval); let year = dateFormat.getFullYear(); @@ -161,16 +163,18 @@ export const USER_ROLES = { }; export const getDatasetNames = (datasets) => { - if(!datasets){return '';} + if (!datasets) { + return ''; + } const datasetNames = datasets.map((dataset) => { - return ((dataset.label) ? dataset.label : dataset.name); + return ((dataset.label) ? dataset.label : dataset.name); }); return datasetNames.join('\n'); }; //helper function to generate keys for rendered elements; splits on commas and whitespace export const convertLabelToKey = (label = '') => { - return label.split(/[\s,]+/) .join('-'); + return label.split(/[\s,]+/).join('-'); }; export const setUserRoleStatuses = (user, Storage) => { @@ -212,7 +216,7 @@ export const Navigation = { export const download = (fileName, text) => { const break_line = '\r\n \r\n'; text = break_line + text; - let blob = new Blob([text], { type: 'text/plain' }); + let blob = new Blob([text], {type: 'text/plain'}); const url = window.URL.createObjectURL(blob); let a = document.createElement('a'); a.href = url; @@ -279,9 +283,9 @@ export const Notifications = { */ export const PromiseSerial = funcs => funcs.reduce((promise, func) => - promise.then(result => - func().then(Array.prototype.concat.bind(result))), - Promise.resolve([])); + promise.then(result => + func().then(Array.prototype.concat.bind(result))), + Promise.resolve([])); ////////////////////////////////// //DAR CONSOLES UTILITY FUNCTIONS// @@ -300,7 +304,7 @@ export const outputCommaSeperatedElectionStatuses = (elections) => { export const getElectionDate = (election) => { let formattedString = '- -'; - if(election) { + if (election) { //NOTE: some elections have a createDate attribute but not a lastUpdate attributes const targetDate = election.lastUpdate || election.createDate; formattedString = formatDate(targetDate); @@ -308,7 +312,7 @@ export const getElectionDate = (election) => { return formattedString; }; -export const wasVoteSubmitted =(vote) => { +export const wasVoteSubmitted = (vote) => { //NOTE: as mentioned elsewhere, legacy code has resulted in multiple sources for timestamps //current code will always provide lastUpdate const targetDate = vote.lastUpdate || vote.createDate || vote.updateDate || vote.lastUpdateDate; @@ -323,20 +327,20 @@ export const wasFinalVoteTrue = (voteData) => { export const processElectionStatus = (election, votes, showVotes) => { let output; - const electionStatus = !isNil(get('status')(election)) ? toLower(election.status) : null; + const electionStatus = !isNil(get('status')(election)) ? toLower(election.status) : null; if (isNil(electionStatus)) { output = 'Unreviewed'; - } else if(electionStatus === 'open') { + } else if (electionStatus === 'open') { //Null check since react doesn't necessarily perform prop updates immediately - if(!isEmpty(votes) && !isNil(election)) { + if (!isEmpty(votes) && !isNil(election)) { const dacVotes = filter((vote) => toLower(vote.type) === 'dac' && vote.electionId === election.electionId)(votes); const completedVotes = (filter(wasVoteSubmitted)(dacVotes)).length; const outputSuffix = `(${completedVotes} / ${dacVotes.length} votes)`; output = `Open${showVotes ? outputSuffix : ''}`; } - //some elections have electionStatus === Final, others have electionStatus === Closed - //both are, in this step of the process, technically referring to a closed election - //therefore both values must be checked for + //some elections have electionStatus === Final, others have electionStatus === Closed + //both are, in this step of the process, technically referring to a closed election + //therefore both values must be checked for } else if (electionStatus === 'final' || electionStatus === 'closed') { const finalVote = find(wasFinalVoteTrue)(votes); output = finalVote ? 'Approved' : 'Denied'; @@ -364,7 +368,7 @@ export const calcVisibleWindow = (currentPage, tableSize, filteredList) => { export const getSearchFilterFunctions = () => { return { dar: (term, targetList) => filter(electionData => { - const { election, dac, votes} = electionData; + const {election, dac, votes} = electionData; const dar = electionData.dar ? electionData.dar.data : undefined; const targetDarAttrs = !isNil(dar) ? JSON.stringify([toLower(dar.projectTitle), toLower(dar.darCode), toLower(getNameOfDatasetForThisDAR(dar.datasets, dar.datasetIds))]) : []; const targetDacAttrs = !isNil(dac) ? JSON.stringify([toLower(dac.name)]) : []; @@ -372,7 +376,7 @@ export const getSearchFilterFunctions = () => { return includes(term, targetDarAttrs) || includes(term, targetDacAttrs) || includes(term, targetElectionAttrs); }, targetList), libraryCard: (term, targetList) => filter(libraryCard => { - const { userName, institution, createDate, updateDate, eraCommonsId, userEmail} = libraryCard; + const {userName, institution, createDate, updateDate, eraCommonsId, userEmail} = libraryCard; const institutionName = institution.name; return includes(term, toLower(userName)) || includes(term, toLower(institutionName)) || @@ -382,7 +386,7 @@ export const getSearchFilterFunctions = () => { includes(term, toLower(eraCommonsId)); }, targetList), signingOfficialResearchers: (term, targetList) => filter(researcher => { - const { displayName, eraCommonsId, email } = researcher; + const {displayName, eraCommonsId, email} = researcher; const roles = researcher.roles || []; const baseAttributes = [displayName, eraCommonsId, email]; const includesRoles = roles.reduce((memo, current) => { @@ -443,6 +447,7 @@ export const getSearchFilterFunctions = () => { * pre-populated with data use codes and translations */ const loweredTerm = toLower(term); + const name = dataset.name; const alias = dataset.alias; const identifier = dataset.datasetIdentifier; const allPropValues = dataset.properties.map((p) => p.propertyValue).join(''); @@ -453,10 +458,44 @@ export const getSearchFilterFunctions = () => { : 'rejected' : 'yes no'; return includes(loweredTerm, toLower(alias)) || - includes(loweredTerm, toLower(identifier)) || - includes(loweredTerm, toLower(allPropValues)) || - includes(loweredTerm, toLower(dataset.codeList)) || - includes(loweredTerm, toLower(status)); + includes(loweredTerm, toLower(name)) || + includes(loweredTerm, toLower(identifier)) || + includes(loweredTerm, toLower(allPropValues)) || + includes(loweredTerm, toLower(dataset.codeList)) || + includes(loweredTerm, toLower(status)); + }, targetList), + datasetTerms: (term, targetList) => filter(datasetTerm => { + /** + * This filter function is intended for Dataset Index Terms + */ + const loweredTerm = toLower(term); + // Approval status + const status = !isNil(datasetTerm.dacApproval) + ? datasetTerm.dacApproval + ? 'accepted' + : 'rejected' + : 'pending'; + const primaryCodes = datasetTerm.dataUse?.primary.map(du => du.code); + const secondaryCodes = datasetTerm.dataUse?.secondary.map(du => du.code); + const codes = join(', ')(concat(primaryCodes)(secondaryCodes)); + const dataTypes = join(', ')(datasetTerm.study?.dataTypes); + const custodians = join(', ')(datasetTerm.study?.dataCustodianEmail); + return includes(loweredTerm, toLower(datasetTerm.datasetName)) || + includes(loweredTerm, toLower(datasetTerm.datasetIdentifier)) || + includes(loweredTerm, toLower(datasetTerm.dacName)) || + includes(loweredTerm, toLower(datasetTerm.dataLocation)) || + includes(loweredTerm, toLower(codes)) || + includes(loweredTerm, toLower(datasetTerm.createUserDisplayName)) || + includes(loweredTerm, toLower(datasetTerm.url)) || + includes(loweredTerm, toLower(datasetTerm.study?.description)) || + includes(loweredTerm, toLower(datasetTerm.study?.dataSubmitterEmail)) || + includes(loweredTerm, toLower(dataTypes)) || + includes(loweredTerm, toLower(custodians)) || + includes(loweredTerm, toLower(datasetTerm.study?.phenotype)) || + includes(loweredTerm, toLower(datasetTerm.study?.piName)) || + includes(loweredTerm, toLower(datasetTerm.study?.species)) || + includes(loweredTerm, toLower(datasetTerm.study?.studyName)) || + includes(loweredTerm, toLower(status)); }, targetList), }; }; @@ -466,13 +505,13 @@ export const tableSearchHandler = (list, setFilteredList, setCurrentPage, modelN return (searchTerms) => { const rawSearchTerms = getOr(searchTerms, 'current.value', searchTerms); const searchTermValues = toLower(rawSearchTerms).split(/\s|,/); - if(isEmpty(searchTermValues)) { + if (isEmpty(searchTermValues)) { setFilteredList(list); } else { let newFilteredList = cloneDeep(list); lodashFPForEach((splitTerm) => { const term = splitTerm.trim(); - if(!isEmpty(term)) { + if (!isEmpty(term)) { const filterFn = filterFnMap[modelName]; newFilteredList = filterFn(term, newFilteredList); } @@ -487,7 +526,7 @@ export const searchOntologies = (query, callback) => { let options = []; DAR.getAutoCompleteOT(query).then( items => { - options = items.map(function(item) { + options = items.map(function (item) { return { key: item.id, value: item.id, @@ -500,7 +539,7 @@ export const searchOntologies = (query, callback) => { }; export const setStyle = (disabled, baseStyle, targetColorAttribute) => { - let appliedStyle = disabled ? {[targetColorAttribute] : Theme.palette.disabled} : {}; + let appliedStyle = disabled ? {[targetColorAttribute]: Theme.palette.disabled} : {}; try { return Object.assign(baseStyle, appliedStyle); } catch (e) { @@ -510,12 +549,12 @@ export const setStyle = (disabled, baseStyle, targetColorAttribute) => { export const setDivAttributes = (disabled, onClick, style, dataTip, onMouseEnter, onMouseLeave, key) => { let attributes; - if(!disabled) { + if (!disabled) { attributes = {onClick, onMouseEnter, onMouseLeave, style, 'data-tip': dataTip, key, id: key}; } else { attributes = {style, disabled, 'data-tip': dataTip, key}; } - if(!isEmpty(dataTip)) { + if (!isEmpty(dataTip)) { attributes['data-tip'] = dataTip; } return attributes; @@ -524,12 +563,11 @@ export const setDivAttributes = (disabled, onClick, style, dataTip, onMouseEnter //each item in the list is an array of metadata representing a single table row //the metadata for each cell needs a data (exactly what is displayed in the table) //or value (string or number alternative) property which determines sorting -export const sortVisibleTable = ({ list = [], sort }) => { +export const sortVisibleTable = ({list = [], sort}) => { // Sort: { dir, colIndex } if (!sort || sort.colIndex === undefined) { return list; - } - else { + } else { return list.sort((a, b) => { const aVal = a[sort.colIndex].value || a[sort.colIndex].data; const bVal = b[sort.colIndex].value || b[sort.colIndex].data; @@ -539,7 +577,7 @@ export const sortVisibleTable = ({ list = [], sort }) => { if (aVal === null || bVal === null) { return (aVal > bVal ? -1 : 1) * sort.dir; } else { - return (aVal.localeCompare(bVal, 'en', { sensitivity: 'base', numeric: true }) * sort.dir); + return (aVal.localeCompare(bVal, 'en', {sensitivity: 'base', numeric: true}) * sort.dir); } } }); @@ -553,7 +591,7 @@ export const recalculateVisibleTable = async ({ try { // Sort data before applying paging if (sort) { - filteredList = sortVisibleTable({ list: filteredList, sort }); + filteredList = sortVisibleTable({list: filteredList, sort}); } // Set paging variables and truncate the list @@ -568,13 +606,13 @@ export const recalculateVisibleTable = async ({ ); setVisibleList(visibleList); } catch (error) { - Notifications.showError({ text: 'Error updating table' }); + Notifications.showError({text: 'Error updating table'}); } }; export const searchOnFilteredList = (searchTerms, originalList, filterFn, setFilteredList) => { let searchList = (!isNil(originalList) ? [...originalList] : []); - if(!isEmpty(searchTerms)) { + if (!isEmpty(searchTerms)) { const terms = searchTerms.split(' '); lodashFPForEach((term => searchList = filterFn(term, searchList)))(terms); } @@ -595,6 +633,6 @@ export const getBooleanFromEventHtmlDataValue = (e) => { export const hasDataSubmitterRole = (user) => { const roles = get('roles')(user); - const dsRole = find({'roleId':8})(roles); + const dsRole = find({'roleId': 8})(roles); return !isNil(dsRole); }; diff --git a/src/pages/researcher_console/DatasetSubmissions.jsx b/src/pages/researcher_console/DatasetSubmissions.jsx new file mode 100644 index 000000000..29c140f91 --- /dev/null +++ b/src/pages/researcher_console/DatasetSubmissions.jsx @@ -0,0 +1,149 @@ +import React, {useCallback, useEffect, useRef, useState} from 'react'; +import {Styles, Theme} from '../../libs/theme'; +import lockIcon from '../../images/lock-icon.png'; +import {Link} from 'react-router-dom'; +import AddCircleOutlineIcon from '@mui/icons-material/AddCircleOutline'; +import {getSearchFilterFunctions, Notifications, searchOnFilteredList} from '../../libs/utils'; +import SearchBar from '../../components/SearchBar'; +import {DataSet} from '../../libs/ajax'; +import DatasetSubmissionsTable from './DatasetSubmissionsTable'; +import {Storage} from '../../libs/storage'; +import styles from './DatasetTerms.module.css'; + +export default function DatasetSubmissions() { + + const [terms, setTerms] = useState([]); + const [filteredTerms, setFilteredTerms] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [currentUser, setCurrentUser] = useState({}); + const searchRef = useRef(''); + + useEffect(() => { + const init = async () => { + const user = Storage.getCurrentUser(); + setCurrentUser(user); + const query = { + 'from': 0, + 'size': 10000, + 'query': { + 'bool': { + 'must': [ + { + 'match': { + '_type': 'dataset' + } + }, + { + 'bool': { + 'should': [ + { + 'term': { + 'createUserId': { + 'value': user.userId + } + } + }, + { + 'term': { + 'study.dataSubmitterId': { + 'value': user.userId + } + } + }, + { + 'term': { + 'study.dataCustodianEmail': { + 'value': user.email + } + } + } + ] + } + } + ] + } + } + }; + setIsLoading(true); + try { + const queryTerms = await DataSet.searchDatasetIndex(query); + setTerms(queryTerms); + setFilteredTerms(queryTerms); + } catch (error) { + Notifications.showError({text: 'Error initializing datasets table'}); + } + setIsLoading(false); + }; + init(); + }, []); + + const handleSearchChange = useCallback((searchTerms) => searchOnFilteredList( + searchTerms, + terms, + getSearchFilterFunctions().datasetTerms, + setFilteredTerms + ), [terms]); + + const addDatasetButtonStyle = { + color: Theme.palette.link, + backgroundColor: 'white', + border: '1px solid', + borderColor: Theme.palette.link, + borderRadius: 4, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + fontSize: '1.45rem', + padding: '3%', + cursor: 'default', + textTransform: 'uppercase', + fontWeight: 600, + marginRight: 5, + marginTop: 10 + }; + + const addDatasetButton = (currentUser.libraryCards?.length > 0) + ? + : ; + + return ( +
+
+
+
+ {'Lock +
+
+
+ My Submitted Datasets +
+
+ View the status of datasets registered in DUOS +
+
{addDatasetButton}
+
+
+
+ +
+
+
+ +
+
+ ); +} \ No newline at end of file diff --git a/src/pages/researcher_console/DatasetSubmissionsTable.jsx b/src/pages/researcher_console/DatasetSubmissionsTable.jsx new file mode 100644 index 000000000..175d91f35 --- /dev/null +++ b/src/pages/researcher_console/DatasetSubmissionsTable.jsx @@ -0,0 +1,123 @@ +import * as React from 'react'; +import {useCallback, useEffect, useState} from 'react'; +import {Notifications} from '../../libs/utils'; +import loadingIndicator from '../../images/loading-indicator.svg'; +import SortableTable from '../../components/sortable_table/SortableTable'; +import {concat, isNil, join} from 'lodash/fp'; +import Button from '@mui/material/Button'; +import styles from './DatasetTerms.module.css'; + + +export default function DatasetSubmissionsTable(props) { + + const spinner =
+ {'Loading'}/ +
; + + const columns = [ + { + id: 'datasetIdentifier', + numeric: false, + disablePadding: false, + label: 'DUOS ID', + }, + { + id: 'datasetName', + numeric: false, + disablePadding: false, + label: 'Dataset Name', + }, + { + id: 'datasetSubmitter', + numeric: false, + disablePadding: false, + label: 'Dataset Submitter', + }, + { + id: 'datasetCustodians', + numeric: false, + disablePadding: false, + label: 'Dataset Custodians', + }, + { + id: 'dac', + numeric: false, + disablePadding: false, + label: 'DAC', + }, + { + id: 'dataUse', + numeric: false, + disablePadding: false, + label: 'Data Use', + }, + { + id: 'status', + numeric: false, + disablePadding: false, + label: 'Status', + }, + { + id: 'actions', + numeric: false, + disablePadding: false, + label: 'Actions', + } + ]; + + const [terms, setTerms] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [rows, setRows] = useState([]); + + // Datasets can be filtered from the parent component and redrawn frequently. + const redrawRows = useCallback(() => { + const rows = terms.map((term) => { + const status = isNil(term.dacApproval) ? 'Pending' : (term.dacApproval ? 'Accepted' : 'Rejected'); + const primaryCodes = term.dataUse?.primary?.map(du => du.code); + const secondaryCodes = term.dataUse?.secondary?.map(du => du.code); + const editLink = (term.study?.studyId) ? '/study_update/' + term.study.studyId : '/dataset_update/' + term.datasetId; + const editButton = (status === 'Accepted') ? +
: +
+ +
; + const custodians = join(', ')(term.study?.dataCustodianEmail); + return { + datasetIdentifier: term.datasetIdentifier, + datasetName: term.datasetName, + dataSubmitter: term.createUserDisplayName, + datasetCustodians: custodians, + dac: term.dacName, + dataUse: join(', ')(concat(primaryCodes)(secondaryCodes)), + status: status, + actions: editButton + }; + }); + setRows(rows); + }, [terms]); + + useEffect(() => { + const init = async () => { + try { + setTerms(props.terms); + setIsLoading(props.isLoading); + redrawRows(); + } catch (error) { + Notifications.showError({text: 'Error: Unable to retrieve datasets from server'}); + } + }; + init(); + }, [props, redrawRows]); + + const sortableTable = ; + + return isLoading ? spinner : sortableTable; +} \ No newline at end of file diff --git a/src/pages/researcher_console/DatasetTerms.module.css b/src/pages/researcher_console/DatasetTerms.module.css new file mode 100644 index 000000000..8538460b9 --- /dev/null +++ b/src/pages/researcher_console/DatasetTerms.module.css @@ -0,0 +1,28 @@ +.submitted-datasets-header { + display: flex; + justify-content: space-between; + width: 112%; + margin-left: -6%; + padding: 0 2.5%; +} + +.term-table-container { + width: 100%; + margin-top: 10px; + margin-left: 22px; +} + +.search-box-container { + width: 50%; + display: flex; + justify-content: flex-end; +} + +.action-button { + font-size: 14px; + border: 1px solid #0948B7; + border-radius: 4px; + height: 25px; + cursor: pointer; + color: #0948B7; +} \ No newline at end of file diff --git a/src/pages/ResearcherConsole.js b/src/pages/researcher_console/ResearcherConsole.js similarity index 71% rename from src/pages/ResearcherConsole.js rename to src/pages/researcher_console/ResearcherConsole.js index f25da0485..e35f62d33 100644 --- a/src/pages/ResearcherConsole.js +++ b/src/pages/researcher_console/ResearcherConsole.js @@ -1,16 +1,18 @@ -import { useState, useEffect, useRef, useCallback } from 'react'; -import { div, h, img, a } from 'react-hyperscript-helpers'; +import {useCallback, useEffect, useRef, useState} from 'react'; +import {a, div, h, img} from 'react-hyperscript-helpers'; import {cloneDeep, findIndex} from 'lodash/fp'; -import { Styles } from '../libs/theme'; -import { Collections, DAR } from '../libs/ajax'; -import { DarCollectionTableColumnOptions, DarCollectionTable } from '../components/dar_collection_table/DarCollectionTable'; -import accessIcon from '../images/lock-icon.png'; -import {Notifications, searchOnFilteredList, getSearchFilterFunctions } from '../libs/utils'; -import SearchBar from '../components/SearchBar'; -import { consoleTypes } from '../components/dar_collection_table/DarCollectionTableCellData'; -import { USER_ROLES } from '../libs/utils'; -import BroadLibraryCardAgreementLink from '../assets/Library_Card_Agreement_2023_ApplicationVersion.pdf'; -import NhgriLibraryCardAgreementLink from '../assets/NIH_Library_Card_Agreement_11_17_22_version.pdf'; +import {Styles} from '../../libs/theme'; +import {Collections, DAR} from '../../libs/ajax'; +import { + DarCollectionTable, + DarCollectionTableColumnOptions +} from '../../components/dar_collection_table/DarCollectionTable'; +import accessIcon from '../../images/lock-icon.png'; +import {getSearchFilterFunctions, Notifications, searchOnFilteredList, USER_ROLES} from '../../libs/utils'; +import SearchBar from '../../components/SearchBar'; +import {consoleTypes} from '../../components/dar_collection_table/DarCollectionTableCellData'; +import BroadLibraryCardAgreementLink from '../../assets/Library_Card_Agreement_2023_ApplicationVersion.pdf'; +import NhgriLibraryCardAgreementLink from '../../assets/NIH_Library_Card_Agreement_11_17_22_version.pdf'; const filterFn = getSearchFilterFunctions().darCollections; @@ -53,9 +55,12 @@ export default function ResearcherConsole() { //cancel collection function, passed to collections table to be used in buttons const cancelCollection = async (darCollection) => { try { - const { darCollectionId, darCode } = darCollection; + const {darCollectionId, darCode} = darCollection; await Collections.cancelCollection(darCollectionId); - const updatedCollection = await Collections.getCollectionSummaryByRoleNameAndId({roleName: USER_ROLES.researcher, id: darCollectionId}); + const updatedCollection = await Collections.getCollectionSummaryByRoleNameAndId({ + roleName: USER_ROLES.researcher, + id: darCollectionId + }); const targetIndex = researcherCollections.findIndex((collection) => collection.darCollectionId === darCollectionId); if (targetIndex < 0) { @@ -75,7 +80,7 @@ export default function ResearcherConsole() { //revise collection function, passed to collections table to be used in buttons const reviseCollection = async (darCollection) => { try { - const { darCollectionId, darCode } = darCollection; + const {darCollectionId, darCode} = darCollection; const draftCollection = await Collections.reviseCollection(darCollectionId); const targetIndex = researcherCollections.findIndex((collection) => collection.darCollectionId === darCollectionId); @@ -96,7 +101,7 @@ export default function ResearcherConsole() { //Draft delete, by referenceIds - const deleteDraftById = async ({ referenceId }) => { + const deleteDraftById = async ({referenceId}) => { const collectionsClone = cloneDeep(researcherCollections); await DAR.deleteDar(referenceId); const targetIndex = findIndex((draft) => { @@ -111,11 +116,11 @@ export default function ResearcherConsole() { }; //Draft delete, passed down to draft table to be used with delete button - const deleteDraft = async ({ referenceIds, darCode }) => { + const deleteDraft = async ({referenceIds, darCode}) => { try { - const targetIndex = deleteDraftById({ referenceId: referenceIds[0] }); + const targetIndex = deleteDraftById({referenceId: referenceIds[0]}); if (targetIndex === -1) { - Notifications.showError({ text: 'Error processing delete request' }); + Notifications.showError({text: 'Error processing delete request'}); } else { Notifications.showSuccess({text: `Deleted Data Access Request Draft ${darCode}`}); } @@ -127,20 +132,20 @@ export default function ResearcherConsole() { }; - return div({ style: Styles.PAGE }, [ - div({ style: { display: 'flex', justifyContent: 'space-between', margin: '0px -3%' } }, [ + return div({style: Styles.PAGE}, [ + div({style: {display: 'flex', justifyContent: 'space-between', margin: '0px -3%'}}, [ div( - { className: 'left-header-section', style: Styles.LEFT_HEADER_SECTION }, + {className: 'left-header-section', style: Styles.LEFT_HEADER_SECTION}, [ - div({ style: Styles.ICON_CONTAINER }, [ + div({style: Styles.ICON_CONTAINER}, [ img({ id: 'access-icon', src: accessIcon, style: Styles.HEADER_IMG, }), ]), - div({ style: Styles.HEADER_CONTAINER }, [ - div({ style: Styles.TITLE }, ['My Data Access Requests']), + div({style: Styles.HEADER_CONTAINER}, [ + div({style: Styles.TITLE}, ['My Data Access Requests']), div( { style: Object.assign({}, Styles.MEDIUM_DESCRIPTION, { @@ -155,14 +160,20 @@ export default function ResearcherConsole() { fontSize: '18px', }), }, - ['By submitting a DAR in DUOS you agree to the ', a({target: '_blank', href: BroadLibraryCardAgreementLink}, ['Broad']), ' and ', a({target: '_blank', href: NhgriLibraryCardAgreementLink}, ['NHGRI']), ' Library Card Agreements.'] + ['By submitting a DAR in DUOS you agree to the ', a({ + target: '_blank', + href: BroadLibraryCardAgreementLink + }, ['Broad']), ' and ', a({ + target: '_blank', + href: NhgriLibraryCardAgreementLink + }, ['NHGRI']), ' Library Card Agreements.'] ), ]), ] ), - h(SearchBar, { handleSearchChange, searchRef }), + h(SearchBar, {handleSearchChange, searchRef}), ]), - div({ className: 'table-container' }, [ + div({className: 'table-container'}, [ h(DarCollectionTable, { collections: filteredList, columns: [