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,
            };
 }());