b99f96b3ed42f3644a19890bbb259ab1ca005008 chmalee Tue Jan 27 11:16:35 2026 -0800 HubSpace: when viewing one specific hub directory and then clicking the upload button, make the default choice for the hub name be the on that is being viewed, refs #36830 diff --git src/hg/js/hgMyData.js src/hg/js/hgMyData.js index 8b80d778fe6..0a5f15745c7 100644 --- src/hg/js/hgMyData.js +++ src/hg/js/hgMyData.js @@ -482,31 +482,31 @@ batchDbGenomeSearchBar.style.gridArea = "2 / 4 / 2 / 4"; let batchDbGenomeSearchButton = document.createElement("input"); batchDbGenomeSearchButton.type = "button"; batchDbGenomeSearchButton.value = "search"; batchDbGenomeSearchButton.id = "batchDbSearchBarButton"; batchDbGenomeSearchButton.style.gridArea = "2 / 5 / 2 / 5"; // the batch change hub name let batchParentDirLabel = document.createElement("label"); batchParentDirLabel.textContent = "Hub Name"; batchParentDirLabel.for = "batchParentDir"; batchParentDirLabel.style.gridArea = "3 / 1 / 3 / 1"; let batchParentDirInput = document.createElement("input"); batchParentDirInput.id = "batchParentDir"; - batchParentDirInput.value = hubCreate.uiState.hubNameDefault; + batchParentDirInput.value = hubCreate.getDefaultHubName(); batchParentDirInput.style.gridArea = "3 / 2 / 3 / 2"; batchParentDirInput.style.margin= "1px 1px auto"; batchParentDirInput.classList.add("uppy-u-reset", "uppy-c-textInput"); // add event handlers to change metadata, use an arrow function // because otherwise 'this' keyword will be the element instead of // our class batchDbSelect.addEventListener("change", (ev) => { let files = this.uppy.getFiles(); let val = ev.target.value; for (let [key, file] of Object.entries(files)) { this.uppy.setFileMeta(file.id, {genome: val}); this.uppy.setFileMeta(file.id, {genomeLabel: ev.target.selectedOptions[0].label}); } }); @@ -541,31 +541,31 @@ if (justInitted) { // only do this once per batch setup batchDbGenomeSearchButton.addEventListener("click", (e) => { let inp = document.getElementById(batchDbSearchBar.id).value; let selector = "[id='"+batchDbGenomeSearchBar.id+"']"; $(selector).autocompleteCat("search", inp); }); } } } install() { this.uppy.on("file-added", (file) => { // add default meta data for genome and fileType console.log("file-added"); - this.uppy.setFileMeta(file.id, {"genome": hubCreate.defaultDb(), "fileType": hubCreate.detectFileType(file.name), "parentDir": hubCreate.uiState.hubNameDefault}); + this.uppy.setFileMeta(file.id, {"genome": hubCreate.defaultDb(), "fileType": hubCreate.detectFileType(file.name), "parentDir": hubCreate.getDefaultHubName()}); if (this.uppy.getFiles().length > 1) { this.addBatchSelectsToDashboard(); } else { // only open the file editor when there is one file const dash = uppy.getPlugin("Dashboard"); dash.toggleFileCard(true, file.id); } }); this.uppy.on("file-removed", (file) => { // remove the batch change selects if now <2 files present if (this.uppy.getFiles().length < 2) { this.removeBatchSelectsFromDashboard(); } }); @@ -608,57 +608,63 @@ uppy.info(`Error: Hub name has special characters, please rename hub: '${file.meta.parentDir}' to only include alpha-numeric characters, period, or underscore.`, 'error', 5000); } } }); } uninstall() { // not really used because we aren't ever uninstalling the uppy instance this.uppy.off("file-added"); } } 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 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 }; 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"], "bigChain": [".bigchain"], "bamIndex": [".bam.bai", ".bai"], "tabixIndex": [".vcf.gz.tbi", "vcf.bgz.tbi"], "hub.txt": ["hub.txt"], "text": [".txt", ".text"], }; + function getDefaultHubName() { + return uiState.currentHub.length > 0 ? uiState.currentHub : uiState.hubNameDefault; + } + function detectFileType(fileName) { let fileLower = fileName.toLowerCase(); for (let fileType in extensionMap) { for (let ext of extensionMap[fileType]) { if (fileLower.endsWith(ext)) { return fileType; } } } //we could alert here but instead just explicitly set the value to null //and let the backend reject it instead, forcing the user to rename their //file //alert(`file extension for ${fileName} not found, please explicitly select it`); return null; } @@ -925,54 +931,56 @@ function clearSearch(table) { // clear any fixed searches so we can apply a new one let currSearches = table.search.fixed().toArray(); currSearches.forEach((name) => table.search.fixed(name, null)); } function dataTableShowTopLevel(table) { // show all the "root" files, which are files (probably mostly directories) // with no parentDir clearSearch(table); // deselect any selected rows like Finder et al when moving into/upto a directory table.rows({selected: true}).deselect(); table.search.fixed("showRoot", function(searchStr, rowData, rowIx) { return !rowData.parentDir; }); + uiState.currentHub = ""; } function dataTableShowDir(table, dirName, dirFullPath) { // show the directory and all immediate children of the directory clearSearch(table); // deselect any selected rows like Finder et al when moving into/upto a directory table.rows({selected: true}).deselect(); table.draw(); // NOTE that the below does not actually render until the next table.draw() call table.search.fixed("oneHub", function(searchStr, rowData, rowIx) { // calculate the fullPath of this rows parentDir in case the dirName passed // to this function has the same name as a parentDir further up in the // listing. For example, consider a test/test/tmp.txt layout, where "test" // is the parentDir of tmp.txt and the test subdirectory let parentDirFull = rowData.fullPath.split("/").slice(0,-1).join("/"); if (rowData.parentDir === dirName && parentDirFull === dirFullPath) { return true; } else if (rowData.fullPath === dirFullPath) { // also return the directory itself return true; } else { return false; } }); + uiState.currentHub = dirName; dataTableCreateBreadcrumb(table, dirName, dirFullPath); } // when we move into a new directory, we remove the row from the table // and add it's html into the header, keep the row object around so // we can add it back in later let oldRowData = null; function dataTableCustomOrder(table, dirData) { // figure out the order the rows of the table should be in // if dirData is null, sort on uploadTime first // if dirData exists, that is the first row, followed by everything else // in uploadTime order if (!dirData) { // make sure the old row can show up again in the table let thead = document.querySelector(".dt-scroll-headInner > table:nth-child(1) > thead:nth-child(1)"); @@ -1568,18 +1576,19 @@ } else if ((url.protocol + "//" + url.host) !== loginHost) { warn(`The hub upload feature is only avaiable on our US based public site (<a href="${loginHost}">${loginHost}</a>) for speed purposes. Please go there to upload your hubs, copy the links to the hub.txt files, then use the Connected Hubs tab here to view your files.`); } else if (!inited && isLoggedIn) { cart.send({ getHubSpaceUIState: {}}, handleRefreshState, handleErrorState); cart.flush(); } else { showExistingFiles([]); } } } return { init: init, uiState: uiState, defaultDb: defaultDb, makeGenomeSelectOptions: makeGenomeSelectOptions, + getDefaultHubName: getDefaultHubName, detectFileType: detectFileType, }; }());