151151 severity =" danger"
152152 text
153153 size =" small"
154- @click =" deleteCasesControlsMaleFile "
154+ @click =" () => deleteCasesControlsFile('male') "
155155 title =" Delete this file"
156156 />
157157 </div >
164164 accept =" .txt,.csv,.tsv"
165165 :showUploadButton =" false"
166166 :previewWidth =" 0"
167- @select =" handleCasesControlsMaleFile "
168- @clear =" resetCasesControlsMaleFile "
169- @remove =" resetCasesControlsMaleFile "
167+ @select =" (e) => handleCasesControlsFile(e, 'male') "
168+ @clear =" () => resetCasesControlsFile('male') "
169+ @remove =" () => resetCasesControlsFile('male') "
170170 customUpload
171171 :multiple =" false"
172172 >
230230 class =" p-button-primary"
231231 icon =" bi-upload"
232232 :disabled =" !casesControlsMaleMappingComplete"
233- @click =" uploadCasesControlsMaleFile "
233+ @click =" () => uploadCasesControlsFile('male') "
234234 raised
235235 />
236236 <div v-if =" !casesControlsMaleMappingComplete" class =" text-sm text-gray-500 mt-2" >
262262 severity =" danger"
263263 text
264264 size =" small"
265- @click =" deleteCasesControlsFemaleFile "
265+ @click =" () => deleteCasesControlsFile('female') "
266266 title =" Delete this file"
267267 />
268268 </div >
275275 accept =" .txt,.csv,.tsv"
276276 :showUploadButton =" false"
277277 :previewWidth =" 0"
278- @select =" handleCasesControlsFemaleFile "
279- @clear =" resetCasesControlsFemaleFile "
280- @remove =" resetCasesControlsFemaleFile "
278+ @select =" (e) => handleCasesControlsFile(e, 'female') "
279+ @clear =" () => resetCasesControlsFile('female') "
280+ @remove =" () => resetCasesControlsFile('female') "
281281 customUpload
282282 :multiple =" false"
283283 >
341341 class =" p-button-primary"
342342 icon =" bi-upload"
343343 :disabled =" !casesControlsFemaleMappingComplete"
344- @click =" uploadCasesControlsFemaleFile "
344+ @click =" () => uploadCasesControlsFile('female') "
345345 raised
346346 />
347347 <div v-if =" !casesControlsFemaleMappingComplete" class =" text-sm text-gray-500 mt-2" >
373373 severity =" danger"
374374 text
375375 size =" small"
376- @click =" deleteCasesControlsBothFile "
376+ @click =" () => deleteCasesControlsFile('both') "
377377 title =" Delete this file"
378378 />
379379 </div >
386386 accept =" .txt,.csv,.tsv"
387387 :showUploadButton =" false"
388388 :previewWidth =" 0"
389- @select =" handleCasesControlsBothFile "
390- @clear =" resetCasesControlsBothFile "
391- @remove =" resetCasesControlsBothFile "
389+ @select =" (e) => handleCasesControlsFile(e, 'both') "
390+ @clear =" () => resetCasesControlsFile('both') "
391+ @remove =" () => resetCasesControlsFile('both') "
392392 customUpload
393393 :multiple =" false"
394394 >
452452 class =" p-button-primary"
453453 icon =" bi-upload"
454454 :disabled =" !casesControlsBothMappingComplete"
455- @click =" uploadCasesControlsBothFile "
455+ @click =" () => uploadCasesControlsFile('both') "
456456 raised
457457 />
458458 <div v-if =" !casesControlsBothMappingComplete" class =" text-sm text-gray-500 mt-2" >
@@ -702,10 +702,12 @@ const activeAccordionIndex = ref(0);
702702
703703const casesControlsMaleFile = ref (null );
704704const casesControlsFemaleFile = ref (null );
705+ const casesControlsBothFile = ref (null );
705706const cooccurrenceFile = ref (null );
706707const cohortDescriptionFile = ref (null );
707708const casesControlsMaleFileName = ref (' ' );
708709const casesControlsFemaleFileName = ref (' ' );
710+ const casesControlsBothFileName = ref (' ' );
709711const cooccurrenceFileName = ref (' ' );
710712const cohortDescriptionFileName = ref (' ' );
711713
@@ -828,33 +830,15 @@ const cooccurrenceMappingComplete = computed(() => {
828830 return requiredCooccurrenceFields .value .every (mapping => mappedValues .includes (mapping));
829831});
830832
831- // Create flipped mapping for API calls (dropdownValue -> columnName)
832- const flippedCasesControlsMaleMapping = computed (() => {
833+ // Helper function to create flipped mapping for API calls (dropdownValue -> columnName)
834+ function createFlippedMapping ( mappingRef ) {
833835 return Object .fromEntries (
834- Object .entries (casesControlsMaleMapping .value ).map (([key , value ]) => [
836+ Object .entries (mappingRef .value ).map (([key , value ]) => [
835837 value,
836838 key,
837839 ])
838840 );
839- });
840-
841- const flippedCasesControlsFemaleMapping = computed (() => {
842- return Object .fromEntries (
843- Object .entries (casesControlsFemaleMapping .value ).map (([key , value ]) => [
844- value,
845- key,
846- ])
847- );
848- });
849-
850- const flippedCooccurrenceMapping = computed (() => {
851- return Object .fromEntries (
852- Object .entries (cooccurrenceMapping .value ).map (([key , value ]) => [
853- value,
854- key,
855- ])
856- );
857- });
841+ }
858842
859843// Computed properties for button tooltips
860844const casesControlsMaleUploadTooltip = computed (() => {
@@ -873,10 +857,18 @@ const casesControlsFemaleUploadTooltip = computed(() => {
873857 return ` Required: ${ missing .join (' , ' )} ` ;
874858});
875859
860+ const casesControlsBothUploadTooltip = computed (() => {
861+ const missing = [];
862+ if (! casesControlsBothMappingComplete .value ) missing .push (' Column Mapping' );
863+
864+ if (missing .length === 0 ) return ' Upload Both Cases/Controls file' ;
865+ return ` Required: ${ missing .join (' , ' )} ` ;
866+ });
867+
876868const cooccurrenceUploadTooltip = computed (() => {
877869 const missing = [];
878870 if (! cooccurrenceMappingComplete .value ) missing .push (' Column Mapping' );
879-
871+
880872 if (missing .length === 0 ) return ' Upload Co-occurrence file' ;
881873 return ` Required: ${ missing .join (' , ' )} ` ;
882874});
@@ -976,6 +968,8 @@ onMounted(async () => {
976968 existingFiles .value .casesControlsMale = fileInfo;
977969 } else if (row .file_type === ' cases_controls_female' ) {
978970 existingFiles .value .casesControlsFemale = fileInfo;
971+ } else if (row .file_type === ' cases_controls_both' ) {
972+ existingFiles .value .casesControlsBoth = fileInfo;
979973 } else if (row .file_type === ' cooccurrence' ) {
980974 existingFiles .value .cooccurrence = fileInfo;
981975 } else if (row .file_type === ' cohort_description' ) {
@@ -1055,10 +1049,14 @@ function handleMetadataUpdated(response) {
10551049async function handleCasesControlsFile (e , gender ) {
10561050 store .showNotification = false ;
10571051
1058- const fileRef = gender === ' male' ? casesControlsMaleFile : casesControlsFemaleFile;
1059- const fileNameRef = gender === ' male' ? casesControlsMaleFileName : casesControlsFemaleFileName;
1060- const fileInfoRef = gender === ' male' ? casesControlsMaleFileInfo : casesControlsFemaleFileInfo;
1061- const mappingRef = gender === ' male' ? casesControlsMaleMapping : casesControlsFemaleMapping;
1052+ const fileRef = gender === ' male' ? casesControlsMaleFile :
1053+ gender === ' female' ? casesControlsFemaleFile : casesControlsBothFile;
1054+ const fileNameRef = gender === ' male' ? casesControlsMaleFileName :
1055+ gender === ' female' ? casesControlsFemaleFileName : casesControlsBothFileName;
1056+ const fileInfoRef = gender === ' male' ? casesControlsMaleFileInfo :
1057+ gender === ' female' ? casesControlsFemaleFileInfo : casesControlsBothFileInfo;
1058+ const mappingRef = gender === ' male' ? casesControlsMaleMapping :
1059+ gender === ' female' ? casesControlsFemaleMapping : casesControlsBothMapping;
10621060
10631061 fileRef .value = e .files [0 ];
10641062 fileNameRef .value = e .files [0 ]? .name || ' ' ;
@@ -1081,25 +1079,18 @@ async function handleCasesControlsFile(e, gender) {
10811079 throw new Error (' No columns found in API response' );
10821080 }
10831081 } catch (error) {
1082+ const genderLabel = gender === ' male' ? ' Male' : gender === ' female' ? ' Female' : ' Both' ;
10841083 toast .add ({
10851084 severity: ' error' ,
10861085 summary: ' File Error' ,
1087- detail: ` Error processing the ${ gender === ' male ' ? ' Male ' : ' Female ' } Cases/Controls file. Please check the file format.` ,
1086+ detail: ` Error processing the ${ genderLabel } Cases/Controls file. Please check the file format.` ,
10881087 life: 5000
10891088 });
10901089 fileInfoRef .value = {};
10911090 mappingRef .value = {};
10921091 }
10931092}
10941093
1095- // Wrapper functions for template usage
1096- function handleCasesControlsMaleFile (e ) {
1097- return handleCasesControlsFile (e, ' male' );
1098- }
1099-
1100- function handleCasesControlsFemaleFile (e ) {
1101- return handleCasesControlsFile (e, ' female' );
1102- }
11031094
11041095async function handleCooccurrenceFile (e ) {
11051096 store .showNotification = false ;
@@ -1142,15 +1133,22 @@ function handleCohortDescriptionFile(e) {
11421133
11431134// Generic upload method for cases/controls files
11441135async function uploadCasesControlsFile (gender ) {
1145- const genderLabel = gender === ' male' ? ' Male' : ' Female' ;
1146- const mappingCompleteRef = gender === ' male' ? casesControlsMaleMappingComplete : casesControlsFemaleMappingComplete;
1147- const fileRef = gender === ' male' ? casesControlsMaleFile : casesControlsFemaleFile;
1148- const fileNameRef = gender === ' male' ? casesControlsMaleFileName : casesControlsFemaleFileName;
1149- const fileInfoRef = gender === ' male' ? casesControlsMaleFileInfo : casesControlsFemaleFileInfo;
1150- const mappingRef = gender === ' male' ? casesControlsMaleMapping : casesControlsFemaleMapping;
1151- const flippedMappingRef = gender === ' male' ? flippedCasesControlsMaleMapping : flippedCasesControlsFemaleMapping;
1152- const statusKey = gender === ' male' ? ' casesControlsMale' : ' casesControlsFemale' ;
1153- const existingFilesKey = gender === ' male' ? ' casesControlsMale' : ' casesControlsFemale' ;
1136+ const genderLabel = gender === ' male' ? ' Male' : gender === ' female' ? ' Female' : ' Both' ;
1137+ const mappingCompleteRef = gender === ' male' ? casesControlsMaleMappingComplete :
1138+ gender === ' female' ? casesControlsFemaleMappingComplete : casesControlsBothMappingComplete;
1139+ const fileRef = gender === ' male' ? casesControlsMaleFile :
1140+ gender === ' female' ? casesControlsFemaleFile : casesControlsBothFile;
1141+ const fileNameRef = gender === ' male' ? casesControlsMaleFileName :
1142+ gender === ' female' ? casesControlsFemaleFileName : casesControlsBothFileName;
1143+ const fileInfoRef = gender === ' male' ? casesControlsMaleFileInfo :
1144+ gender === ' female' ? casesControlsFemaleFileInfo : casesControlsBothFileInfo;
1145+ const mappingRef = gender === ' male' ? casesControlsMaleMapping :
1146+ gender === ' female' ? casesControlsFemaleMapping : casesControlsBothMapping;
1147+ const flippedMapping = createFlippedMapping (mappingRef);
1148+ const statusKey = gender === ' male' ? ' casesControlsMale' :
1149+ gender === ' female' ? ' casesControlsFemale' : ' casesControlsBoth' ;
1150+ const existingFilesKey = gender === ' male' ? ' casesControlsMale' :
1151+ gender === ' female' ? ' casesControlsFemale' : ' casesControlsBoth' ;
11541152
11551153 if (! mappingCompleteRef .value ) {
11561154 toast .add ({
@@ -1169,7 +1167,7 @@ async function uploadCasesControlsFile(gender) {
11691167 cohortId,
11701168 ` cases_controls_${ gender} ` ,
11711169 ` cases_controls_${ gender} ` ,
1172- flippedMappingRef . value
1170+ flippedMapping
11731171 );
11741172
11751173 // Mark as uploaded and update UI
@@ -1241,14 +1239,6 @@ async function uploadCasesControlsFile(gender) {
12411239 }
12421240}
12431241
1244- // Wrapper functions for template usage
1245- function uploadCasesControlsMaleFile () {
1246- return uploadCasesControlsFile (' male' );
1247- }
1248-
1249- function uploadCasesControlsFemaleFile () {
1250- return uploadCasesControlsFile (' female' );
1251- }
12521242
12531243async function uploadCooccurrenceFile () {
12541244 if (! cooccurrenceMappingComplete .value ) {
@@ -1268,7 +1258,7 @@ async function uploadCooccurrenceFile() {
12681258 cohortId,
12691259 ' cooccurrence' ,
12701260 ' cooccurrence' ,
1271- flippedCooccurrenceMapping . value
1261+ createFlippedMapping (cooccurrenceMapping)
12721262 );
12731263
12741264 // Mark as uploaded and update UI
@@ -1414,11 +1404,16 @@ async function uploadCohortDescriptionFile() {
14141404
14151405// Generic reset function for cases/controls files
14161406function resetCasesControlsFile (gender ) {
1417- const fileRef = gender === ' male' ? casesControlsMaleFile : casesControlsFemaleFile;
1418- const fileNameRef = gender === ' male' ? casesControlsMaleFileName : casesControlsFemaleFileName;
1419- const fileInfoRef = gender === ' male' ? casesControlsMaleFileInfo : casesControlsFemaleFileInfo;
1420- const mappingRef = gender === ' male' ? casesControlsMaleMapping : casesControlsFemaleMapping;
1421- const statusKey = gender === ' male' ? ' casesControlsMale' : ' casesControlsFemale' ;
1407+ const fileRef = gender === ' male' ? casesControlsMaleFile :
1408+ gender === ' female' ? casesControlsFemaleFile : casesControlsBothFile;
1409+ const fileNameRef = gender === ' male' ? casesControlsMaleFileName :
1410+ gender === ' female' ? casesControlsFemaleFileName : casesControlsBothFileName;
1411+ const fileInfoRef = gender === ' male' ? casesControlsMaleFileInfo :
1412+ gender === ' female' ? casesControlsFemaleFileInfo : casesControlsBothFileInfo;
1413+ const mappingRef = gender === ' male' ? casesControlsMaleMapping :
1414+ gender === ' female' ? casesControlsFemaleMapping : casesControlsBothMapping;
1415+ const statusKey = gender === ' male' ? ' casesControlsMale' :
1416+ gender === ' female' ? ' casesControlsFemale' : ' casesControlsBoth' ;
14221417
14231418 fileRef .value = null ;
14241419 fileNameRef .value = ' ' ;
@@ -1427,14 +1422,6 @@ function resetCasesControlsFile(gender) {
14271422 uploadStatus .value [statusKey] = false ;
14281423}
14291424
1430- // Wrapper functions for template usage
1431- function resetCasesControlsMaleFile () {
1432- return resetCasesControlsFile (' male' );
1433- }
1434-
1435- function resetCasesControlsFemaleFile () {
1436- return resetCasesControlsFile (' female' );
1437- }
14381425
14391426function resetCooccurrenceFile () {
14401427 cooccurrenceFile .value = null ;
@@ -1452,9 +1439,11 @@ function resetCohortDescriptionFile() {
14521439
14531440// Generic delete function for cases/controls files
14541441async function deleteCasesControlsFile (gender ) {
1455- const genderLabel = gender === ' male' ? ' Male' : ' Female' ;
1456- const statusKey = gender === ' male' ? ' casesControlsMale' : ' casesControlsFemale' ;
1457- const existingFilesKey = gender === ' male' ? ' casesControlsMale' : ' casesControlsFemale' ;
1442+ const genderLabel = gender === ' male' ? ' Male' : gender === ' female' ? ' Female' : ' Both' ;
1443+ const statusKey = gender === ' male' ? ' casesControlsMale' :
1444+ gender === ' female' ? ' casesControlsFemale' : ' casesControlsBoth' ;
1445+ const existingFilesKey = gender === ' male' ? ' casesControlsMale' :
1446+ gender === ' female' ? ' casesControlsFemale' : ' casesControlsBoth' ;
14581447
14591448 if (! existingFiles .value [existingFilesKey]? .id ) return ;
14601449
@@ -1483,14 +1472,6 @@ async function deleteCasesControlsFile(gender) {
14831472 }
14841473}
14851474
1486- // Wrapper functions for template usage
1487- function deleteCasesControlsMaleFile () {
1488- return deleteCasesControlsFile (' male' );
1489- }
1490-
1491- function deleteCasesControlsFemaleFile () {
1492- return deleteCasesControlsFile (' female' );
1493- }
14941475
14951476async function deleteCooccurrenceFile () {
14961477 if (! existingFiles .value .cooccurrence ? .id ) return ;
0 commit comments