4fc775d4d4ce03a5e1236a5ce1e266b5a0a5e68e
chmalee
  Fri Mar 6 11:13:42 2026 -0800
database name in menubar links needs to include the hubUrl and hub_id when making a link to a non-genark assembly hub, refs #36535

diff --git src/hg/js/utils.js src/hg/js/utils.js
index 1cd28c0b827..47cc16ab302 100644
--- src/hg/js/utils.js
+++ src/hg/js/utils.js
@@ -4449,30 +4449,34 @@
     if (existingItem) {
         let existingLabel = existingItem.label || '';
         let newLabel = cleanItem.label || '';
         // Preserve the existing label if it's more descriptive
         if (existingLabel.includes('(') || existingLabel.length > newLabel.length) {
             cleanItem.label = existingLabel;
         }
         // Preserve category if not present in new item
         if (!cleanItem.category && existingItem.category) {
             cleanItem.category = existingItem.category;
         }
         // Preserve hubUrl if not present in new item
         if (!cleanItem.hubUrl && existingItem.hubUrl) {
             cleanItem.hubUrl = existingItem.hubUrl;
         }
+        // Preserve hubName if not present in new item
+        if (!cleanItem.hubName && existingItem.hubName) {
+            cleanItem.hubName = existingItem.hubName;
+        }
     }
 
     // Add to front
     stack.unshift(key);
     recentObj.results[key] = cleanItem;
 
     window.localStorage.setItem("recentGenomes", JSON.stringify(recentObj));
 }
 
 function getRecentGenomes() {
     // Retrieve recent genome selections from localStorage, formatted for autocomplete display.
     // Preserves original category for re-selection logic, adds displayCategory for UI.
     let stored = window.localStorage.getItem("recentGenomes");
     if (!stored) return [];
 
@@ -4541,30 +4545,42 @@
             newStack.push(key);
         }
     }
     recentObj.stack = newStack;
     window.localStorage.setItem("recentGenomes", JSON.stringify(recentObj));
 }
 
 
 function recentGenomeHref(res) {
     // Build an hgTracks URL for a recent genome entry. GenArk assemblies are
     // handled transparently by fixUpDb() in cartNew() when given just db= with
     // the accession. UCSC native databases also just need db=.
     let db = res.db || res.genome;
     let url = new URL("../cgi-bin/hgTracks", window.location.href);
     url.searchParams.set("hgsid", getHgsid());
+    if (res.hubUrl) {
+        if (res.category && res.category.startsWith("Assembly Hub")) {
+            url.searchParams.set("hubUrl", res.hubUrl);
+            if (res.hubName)
+                db = res.hubName + "_" + db;
+        } else if (!res.category) {
+            // in practice this shouldn't happen, but just in case:
+            let msg = "recentGenomeHref: item has hubUrl but no category: " + JSON.stringify(res);
+            console.warn(msg);
+            writeToApacheLog(msg);
+        }
+    }
     url.searchParams.set("db", db);
     url.searchParams.set("position", "lastDbPos");
     return url.toString();
 }
 
 function addRecentGenomesToMenuBar() {
     // Retrieve recent genome selections from localStorage and add them to the "Genomes" menu heading
     // Tries not add duplicate genomes
     let stored = window.localStorage.getItem("recentGenomes");
     if (!stored) return;
 
     let recentObj = JSON.parse(stored);
     let results = [];
     for (let genome of recentObj.stack) {
         if (recentObj.results[genome]) {