37aae4a2c5a919c329378f3da0792e168426537d chmalee Tue Aug 11 11:31:52 2026 -0700 hgMyData: a blank hub genome means unset, not a mismatch, refs #37964 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> diff --git src/hg/js/hgMyData.js src/hg/js/hgMyData.js index 61279a1f70d..9cc198a57b4 100644 --- src/hg/js/hgMyData.js +++ src/hg/js/hgMyData.js @@ -532,41 +532,45 @@ doUpload = false; continue; } // Hub-level files in a split-hub batch intentionally carry empty genome. if (!file.meta.genome && file.meta.batchSplitHub !== "true") { uppy.info(`Error: No genome selected for file ${file.meta.name}!`, 'error', 5000); doUpload = false; continue; } if (!file.meta.fileType) { uppy.info(`Error: File type not supported, file: ${file.meta.name}!`, 'error', 5000); doUpload = false; continue; } // check if this hub already exists and the genome is different from what was - // just selected, if so, make the user create a new hub - if (file.meta.parentDir in hubCreate.uiState.filesHash && hubCreate.uiState.filesHash[file.meta.parentDir].genome !== file.meta.genome) { + // just selected, if so, make the user create a new hub. A blank genome means + // none has been set yet, not a hub for a genome named "": a directory row is + // blank until an upload carrying a genome lands in it, and the hub level + // files of a hub that brings its own hub.txt have no genome of their own. + // So a blank on either side is not a mismatch. let existing = hubCreate.uiState.filesHash[file.meta.parentDir]; + if (existing && existing.genome && existing.genome !== file.meta.genome) { // If the existing hub is an assembly hub, adopt its genome // automatically rather than erroring - the UI hid the picker // for this case, so the mismatch is just stale metadata. if (existing.hubType === "assemblyHub") { file.meta.genome = existing.genome; file.meta.genomeLabel = existing.genome; file.meta.hubType = "assemblyHub"; - } else { + } else if (file.meta.genome) { uppy.info(`Error: the hub ${file.meta.parentDir} already exists and is for genome "${existing.genome}". Please select the correct genome, a different hub or make a new hub.`, 'error', 10000); doUpload = false; continue; } } // check if the user is uploading a file that already exists in this hub if (file.meta.parentDir in hubCreate.uiState.filesHash) { let hubFiles = hubCreate.uiState.filesHash[file.meta.parentDir].children; for (let j = 0; j < hubFiles.length; j++) { if (hubFiles[j].fileName === file.meta.name) { filesToOverwrite.push(file); break; } } } @@ -1367,31 +1371,32 @@ } } var hubCreate = (function() { let uiState = { // our object for keeping track of the current UI and what to do userUrl: "", // the web accesible path where the uploads are stored for this user hubNameDefault: "", currentHub: "", // if the user has a hub dir open, set the name here and use it as the default // hub name when uploading a new file with the dir open, otherwise hubNameDefault currentHubPath: "", // full path of the open dir, so we can tell which hub it belongs to // when it is a subdirectory like myHub/hg38 isLoggedIn: "", maxQuota: 0, userQuota: 0, userFiles: {}, // same as uiData.userFiles on page load - filesHash: {}, // for each file, userFiles.fullPath is the key, and then the userFiles.fileList data as the value, with an extra key for the child fullPaths if the file is a directory + // Object.create(null) because a hub may be named 'constructor' or 'toString' + filesHash: Object.create(null), // for each file, userFiles.fullPath is the key, and then the userFiles.fileList data as the value, with an extra key for the child fullPaths if the file is a directory }; let extensionMap = { "bigBed": [".bb", ".bigbed"], "bam": [".bam"], "vcf": [".vcf"], "vcfTabix": [".vcf.gz", "vcf.bgz"], "bigWig": [".bw", ".bigwig"], "hic": [".hic"], "cram": [".cram"], "bigBarChart": [".bigbarchart"], "bigGenePred": [".bgp", ".biggenepred"], "bigMaf": [".bigmaf"], "bigInteract": [".biginteract"], "bigPsl": [".bigpsl"], @@ -2463,31 +2468,31 @@ } } function deleteFileFromTable(pathList) { // req is an object with properties of an uploaded file, make a new row // for it in the filesTable let table = $("#filesTable").DataTable(); let rows = table.rows((idx, data) => pathList.includes(data.fullPath)); rows.remove().draw(); let toKeep = (elem) => !pathList.includes(elem.fullPath); pathList.forEach((f) => { updateQuota(-uiState.filesHash[f].fileSize); }); uiState.fileList = uiState.fileList.filter(toKeep); // Rebuild filesHash from remaining fileList to remove stale entries - uiState.filesHash = {}; + uiState.filesHash = Object.create(null); parseFileListIntoHash(uiState.fileList); // If the currently viewed hub directory was deleted (its data is in oldRowData // because dataTableCustomOrder moved it to the header), clean up that stale state if (oldRowData && pathList.includes(oldRowData.fullPath)) { let thead = document.querySelector( ".dt-scroll-headInner > table:nth-child(1) > thead:nth-child(1)"); if (thead && thead.childNodes.length > 1) { thead.removeChild(thead.lastChild); } oldRowData = null; dataTableShowTopLevel(table); dataTableEmptyBreadcrumb(table); table.order([{name: "uploadTime", dir: "desc"}]); table.draw(); }