03d6935afd1f21e64a308f28fe738cd22c0c5b25 chmalee Mon Feb 9 14:05:16 2026 -0800 hgGateway: rename category labels in the 'recents' section. external hub clicks on cards no longer remain selected after clicking. GenArk and native dbs are handled the same for UI purposes, refs #34078 diff --git src/hg/js/hgGateway.js src/hg/js/hgGateway.js index 3889fc2d98f..902abde49e2 100644 --- src/hg/js/hgGateway.js +++ src/hg/js/hgGateway.js @@ -329,32 +329,32 @@ title: hub.longLabel }); text.onclick = function() {hgGateway.onClickHubName(hub.hubUrl, hub.taxId, hub.defaultDb, hub.name);}; svg.appendChild(text); } function drawHubs(svg, hubList, yIn) { // Add a label for each hub in hubList, with a separator line below and // "Hub Genomes" link instead of a tree. var y = yIn; var hub, i, textX, textY, lineX1, lineY, lineX2; var countNonCurated = 0; if (hubList && hubList.length) { for (i = 0; i < hubList.length; i++) { hub = hubList[i]; - // is this a curated assembly hub? If so, don't list it - if (!(hub.hubUrl.startsWith("/gbdb") && ! hub.hubUrl.startsWith("/gbdb/genark"))) { + // Skip UCSC-hosted hubs (native and GenArk) under /gbdb + if (!hub.hubUrl.startsWith("/gbdb")) { addHubLabel(svg, hub, y); y += cfg.labelLineHeight; countNonCurated++; } } if (countNonCurated) { textX = cfg.labelRightX + cfg.speciesLineOffsetX; textY = (yIn + y - cfg.labelLineHeight) / 2; addTrackHubsLink(svg, textX, textY); lineX1 = cfg.hubLineOffset; lineY = y - cfg.halfTextHeight; lineX2 = cfg.containerWidth - cfg.speciesLineOffsetX; addLine(svg, lineX1, lineY, lineX2, lineY); y += cfg.labelLineHeight; } @@ -1116,36 +1116,36 @@ function addHubsToList(hubList) { // Render connected hubs into the connected hubs section // Only show the section if there are non-curated hubs to display var $title = $('#connectedHubsTitle'); var $section = $('#connectedHubsSection'); var $panel = $('#connectedHubsList'); if (!hubList || hubList.length === 0) { // No hubs, hide the section $title.hide(); $section.hide(); return; } - // Filter out curated assembly hubs (those in /gbdb but not /gbdb/genark) - // and convert hub objects to card-compatible format + // Filter out UCSC-hosted hubs (native and GenArk) under /gbdb + // and convert remaining hub objects to card-compatible format var displayHubs = []; hubList.forEach(function(hub) { - // Skip curated assembly hubs (same logic as drawHubs) - if (hub.hubUrl.startsWith("/gbdb") && !hub.hubUrl.startsWith("/gbdb/genark")) { + // Skip UCSC-hosted hubs (native and GenArk) under /gbdb + if (hub.hubUrl.startsWith("/gbdb")) { return; } // Convert hub object to card-compatible format var hubItem = { label: hub.shortLabel + ' (' + hub.assemblyCount + ' assembl' + (hub.assemblyCount === 1 ? 'y' : 'ies') + ')', genome: hub.defaultDb, category: 'Assembly Hub', hubUrl: hub.hubUrl, taxId: hub.taxId, db: hub.defaultDb, hubName: hub.name, longLabel: hub.longLabel }; displayHubs.push(hubItem); @@ -1486,65 +1486,69 @@ if (!isGenomeAtFrontOfRecents(dbForRecents)) { // Construct a descriptive label that includes the db/accession for identification var label = uiState.genomeLabel || uiState.genome; if (label && dbForRecents && label.indexOf(dbForRecents) < 0) { // Add the db/accession to the label if not already present label = label + ' (' + dbForRecents + ')'; } var recentItem = { db: dbForRecents, genome: uiState.genome, label: label, taxId: uiState.taxId }; if (uiState.hubUrl) { recentItem.hubUrl = uiState.hubUrl; - // For hub genomes, add category for proper detection when re-selected - if (dbForRecents.startsWith('GCA_') || dbForRecents.startsWith('GCF_')) { - recentItem.category = "UCSC GenArk"; + if (uiState.hubUrl.startsWith("/gbdb")) { + recentItem.category = "UCSC Curated"; + } else { + recentItem.category = "Assembly Hub"; } + } else { + recentItem.category = "UCSC Curated"; } addRecentGenome(recentItem); } displayRecentGenomesInPanel(); } else { console.log('handleSetDb ignoring: ' + trackHubSkipHubName(jsonData.db) + ' !== ' + trackHubSkipHubName(uiState.db)); } } function handleSetTaxId(jsonData) { // Handle the server's response to the setTaxId cartJson command. if (checkJsonData(jsonData, 'handleSetTaxId') && jsonData.taxId === uiState.taxId) { // Update uiState with new values and update the page: _.assign(uiState, jsonData); updateFindPositionSection(uiState); // Save to recent genomes only if not already at the front (autocompleteCat.js may have just added it) // Use db without hub prefix for consistent key comparison var dbForRecents = trackHubSkipHubName(uiState.db); if (!isGenomeAtFrontOfRecents(dbForRecents)) { // Construct a descriptive label that includes the db for identification var label = uiState.genomeLabel || uiState.genome; if (label && dbForRecents && label.indexOf(dbForRecents) < 0) { // Add the db to the label if not already present label = label + ' (' + dbForRecents + ')'; } addRecentGenome({ db: dbForRecents, genome: uiState.genome, label: label, - taxId: uiState.taxId + taxId: uiState.taxId, + category: "UCSC Curated" }); } displayRecentGenomesInPanel(); } else { console.log('handleSetTaxId ignoring: ' + jsonData.taxId + ' !== ' + uiState.taxId); } } // UI Event Handlers function clearWatermarkInput($input, watermark) { // Note: it is not necessary to re-.Watermark if we upgrade the plugin to version >= 3.1 $input.css('color', 'black'); $input.val('').Watermark(watermark ,'#686868'); @@ -1823,72 +1827,73 @@ $panel.empty(); if (!items || items.length === 0) { if (emptyMessage) { $panel.html('<div class="recentGenomesEmpty">' + emptyMessage + '</div>'); } return; } var clickHandler = onCardClick || setDbFromAutocomplete; // Render each item as a card (vertical layout) items.forEach(function(item) { var $card = $('<div class="recentGenomeCard"></div>'); var label = item.label || item.shortLabel || item.value || item.genome || item.commonName; - var genome = item.genome || item.db || ''; + var genome = trackHubSkipHubName(item.genome || item.db || ''); $card.append('<div class="recentGenomeLabel">' + escapeHtml(label) + '</div>'); if (genome && label.indexOf(genome) < 0) { $card.append('<div class="recentGenomeDb">' + escapeHtml(genome) + '</div>'); } - // Add category as small label - if (item.category) { - var shortCategory = item.category; - if (shortCategory.indexOf('UCSC Genome Browser') >= 0) { - shortCategory = 'UCSC'; - } else if (shortCategory.indexOf('GenArk') >= 0) { - shortCategory = 'GenArk'; - } else if (shortCategory.indexOf('Assembly Hub') >= 0) { - shortCategory = 'Hub'; + // Add category label: "External" for assembly hubs, "UCSC Curated" for everything else. + // The indexOf check handles both the new "Assembly Hub" category from handleSetDb + // and legacy localStorage entries from addHubsToList or older code. + var shortCategory; + if (item.category && item.category.indexOf('Assembly Hub') >= 0) { + shortCategory = 'External'; + } else { + shortCategory = 'UCSC Curated'; } $card.append('<div class="recentGenomeCategory">' + escapeHtml(shortCategory) + '</div>'); - } // Store item data for click handler $card.data('item', item); $card.on('click', function() { var clickedItem = $(this).data('item'); clickHandler(clickedItem); // Highlight selected card in this panel $panel.find('.recentGenomeCard').removeClass('selected'); $(this).addClass('selected'); }); $panel.append($card); }); } function displayRecentGenomesInPanel() { // Display recent genomes in the panel on page load and after genome selection var recentGenomes = getRecentGenomes(); // Show the section (hidden by default in HTML) $('#recentGenomesTitle').show(); $('#recentGenomesSection').show(); var emptyMessage = 'Search for a genome above, or click a popular species icon'; renderGenomeCards(recentGenomes, $('#recentGenomesList'), emptyMessage); + // Clear any selected state from connected hub cards (selection was transient, + // the genome is now reflected in the recent genomes panel) + $('#connectedHubsList .recentGenomeCard').removeClass('selected'); } function escapeHtml(text) { // Simple HTML escape for display if (!text) return ''; return String(text) .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"'); } function init() { // Boot up the page; initialize elements and install event handlers. var searchObj = {};