2f4dc5368794ef8eb09e43c27420703b7cf6135f chmalee Mon Feb 23 11:22:17 2026 -0800 Save ucsc databases to 'Genomes' menu bar recents list when adding genomes to the recents list from not hgGateway. Make urls to genark hubs correct, refs #36535 diff --git src/hg/js/utils.js src/hg/js/utils.js index 4351a59028a..596622cb539 100644 --- src/hg/js/utils.js +++ src/hg/js/utils.js @@ -4497,47 +4497,67 @@ if (!stored) return; let recentObj = JSON.parse(stored); let newStack = []; for (let key of recentObj.stack) { let item = recentObj.results[key]; if (item && item.hubUrl === hubUrl) { delete recentObj.results[key]; } else { 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 need + // db=, genome=, and a fully qualified hubUrl= so that fixUpDb() and + // hubConnectLoadHubs() in cartNew() can connect the hub. UCSC native + // databases just need db=. + let db = res.db || res.genome; + let url = new URL("../cgi-bin/hgTracks", window.location.href); + url.searchParams.set("hgsid", getHgsid()); + url.searchParams.set("db", db); + url.searchParams.set("position", "lastDbPos"); + if (res.hubUrl) { + // The findGenome API returns a relative hubUrl (e.g. GCA/.../hub.txt) + // while hgGateway stores it already prefixed (e.g. /gbdb/genark/GCA/.../hub.txt). + let hubUrl = res.hubUrl; + if (!hubUrl.startsWith("/gbdb/genark/")) { + hubUrl = "/gbdb/genark/" + hubUrl; + } + url.searchParams.set("genome", db); + url.searchParams.set("hubUrl", window.location.origin + hubUrl); + } + 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]) { let item = document.createElement("li"); let link = document.createElement("a"); - // TODO: these links need to work if the result (ie: genark) does not have a db - let res = recentObj.results[genome]; - dbOrGenome = 'hubUrl' in res ? res.hubName + "_" + res.db : res.db; - link.href = "../cgi-bin/hgTracks?hgsid=" + getHgsid() + "&db=" + dbOrGenome + "&position=lastDbPos"; - link.textContent = res.label; + link.href = recentGenomeHref(recentObj.results[genome]); + link.textContent = recentObj.results[genome].label; item.appendChild(link); results.push(item); } } // construct the current list of labels const labelList = []; document.querySelectorAll("#tools1 > ul > li > a").forEach( (a) => { labelList.push(a.textContent); }); // filter our list of recents against the list of "Genomes" let finalResult = results.filter( (result) => { return !labelList.includes(result.firstChild.textContent); }); @@ -4752,35 +4772,35 @@ // process the hubApi/findGenome?q= result set into somthing // jquery-ui autocomplete can use let data = []; let apiSkipList = new Set(["downloadTime", "downloadTimeStamp", "availableAssemblies", "browser", "elapsedTimeMs", "itemCount", "q", "totalMatchCount", "liftable"]); Object.keys(result).forEach((key) => { if (!(apiSkipList.has(key))) { let val = result[key]; let d = { "genome": key, "label": `${val.commonName} (${key})`, }; Object.keys(val).forEach((vkey) => { d[vkey] = val[vkey]; }); + // Set db to the key (database name or accession) so the autocomplete + // select handler can save it to recent genomes + d.db = key; if (val.hubUrl !== null) { d.category = "UCSC GenArk - bulk annotated assemblies from NCBI GenBank / Refseq"; - // For GenArk items, ensure db is set to the accession (key) for consistent - // identification in recent genomes storage (avoids duplicate entries) - d.db = key; } else { d.category = "UCSC Genome Browser assemblies - annotation tracks curated by UCSC"; } data.push(d); } }); return data; } function initSpeciesAutoCompleteDropdown(inputId, selectFunction, baseUrl = null, watermark = null, onServerReply = null, onError = null) { /* Generic function for turning an <input> element into a species search bar with an autocomplete * list separating results by category. * Required arguments: * inputId: id of the input element itself, not created here