835f3f2b9a18f63af202b71477744469e647b328
jcasper
  Tue Jul 21 08:32:17 2026 -0700
Moving track description link to a more visible place and fixing
hub ID parsing.  Old method (parsing trackHubs cart variable) was failing as the contents can now be
hubId:chainId (for quickLift).  New approach uses a library function.  refs #36320

diff --git src/hg/hgTrackUi/hgTrackUi.c src/hg/hgTrackUi/hgTrackUi.c
index 842e8d53a84..6eb860710ac 100644
--- src/hg/hgTrackUi/hgTrackUi.c
+++ src/hg/hgTrackUi/hgTrackUi.c
@@ -3874,30 +3874,42 @@
 	    safef(longLabel, sizeof(longLabel), "%s - Annotation Release %s", tdb->longLabel, trackVersion->version);
 	    }
 	else
 	    safef(longLabel, sizeof(longLabel), "%s", tdb->longLabel);
 	}
     printf("<B style='font-size:200%%;'>%s%s</B>\n", longLabel, tdbIsSuper(tdb) ? " Tracks" : "");
     }
 else
     {
     if (trackDbSetting(tdb, "wgEncode"))
         printf("<A HREF='/ENCODE/index.html'><IMG style='vertical-align:middle;' "
                "width=100 src='/images/ENCODE_scaleup_logo.png'><A>");
     // set large title font size, but less so for long labels to minimize wrap
     printf("<B style='font-size:%d%%;'>%s%s</B>\n", strlen(tdb->longLabel) > 30 ? 133 : 200,
                 tdb->longLabel, tdbIsSuper(tdb) ? " tracks" : "");
+
+    // Add a description link if there is one.  Only for faceted composites for now.
+    if (isNotEmpty(tdb->html) && (tdbIsComposite(tdb) && sameOk(trackDbLocalSetting(tdb, "compositeTrack"), "faceted")))
+        {
+        char *downArrow = "&dArr;";
+        enum browserType browser = cgiBrowser();
+        if (browser == btIE || browser == btFF)
+            downArrow = "&darr;";
+        printf("&nbsp;&nbsp;(<A HREF='#TRACK_HTML' TITLE='Jump to description section of page'>"
+               "Description%s</A>)", downArrow);
+        }
+
     }
 
 
 /* Print link for parent track */
 if (!ajax)
     {
     if (!tdb->parent)
         {
         // show group info
         struct grp *grp, *grps = hLoadGrps(database);
         for (grp = grps; grp != NULL; grp = grp->next)
             {
             if (sameString(grp->name,tdb->grp))
                 {
                 printf("&nbsp;&nbsp;<B style='font-size:100%%;'>"
@@ -4095,44 +4107,30 @@
             downArrow = "&darr;";
         printf("&nbsp;&nbsp;<A HREF='#DISPLAY_SUBTRACKS' TITLE='Jump to subtrack list section of "
                "page'>Subtracks%s</A>", downArrow);
         if (isNotEmpty(tdb->html))
             {
             printf("&nbsp;&nbsp;<A HREF='#TRACK_HTML' TITLE='Jump to description section of page'>"
                    "Description%s</A>", downArrow);
             }
         if (trackDbSetting(tdb, "wgEncode") && isEncode2(database, tdb->track))
             {
             printf("&nbsp;&nbsp;<A HREF='#TRACK_CREDITS' TITLE='Jump to ENCODE lab contacts for this data'>"
                "Contact%s</A>", downArrow);
             }
         printf("&nbsp;</span>");
         }
-    else if (tdbIsComposite(tdb) && sameOk(trackDbLocalSetting(tdb, "compositeTrack"), "faceted"))
-        {
-        char *downArrow = "&dArr;";
-        enum browserType browser = cgiBrowser();
-        if (browser == btIE || browser == btFF)
-            downArrow = "&darr;";
-        if (isNotEmpty(tdb->html))
-            {
-            printf("\n&nbsp;&nbsp;<span id='navDown' style='float:right; display:none;'>");
-            printf("&nbsp;&nbsp;<A HREF='#TRACK_HTML' TITLE='Jump to description section of page'>"
-                   "Description%s</A>", downArrow);
-            printf("&nbsp;</span>");
-            }
-        }
     }
 if (!tdbIsSuperTrack(tdb) && !tdbIsComposite(tdb))
     puts("<BR>");
 
 if (tdbIsDownloadsOnly(tdb))             // Composites without tracks but with files to download
     filesDownloadUi(database,cart,tdb);  // are tdb->type: downloadsOnly
 else
     specificUi(tdb, tdbList, ct, ajax);
 
 // Decorator UI
 struct slName *decoratorSettings = trackDbSettingsWildMatch(tdb, "decorator.*");
 if (decoratorSettings)
     {
     char *browserVersion;
     if (btIE == cgiClientBrowser(&browserVersion, NULL, NULL) && *browserVersion < '8')
@@ -4338,44 +4336,40 @@
  * it as the page content. */
 {
 char *genome = NULL;
 getDbAndGenome(cart, &database, &genome, NULL);
 initGenbankTableNames(database);
 
 char *fileUrl = cartOptionalString(cart, "fileUrl");
 char *urlClone = cloneString(fileUrl);
 cgiDecode(urlClone, urlClone, strlen(urlClone));
 fileUrl = resolveDotDots(urlClone);
 freeMem(urlClone);
 
 boolean matchFound = FALSE;
 
 // Check if fileUrl falls under a connected hub's base directory
-struct slName *hubIds = hubConnectHubsInCart(cart);
-struct slName *thisHubId = hubIds;
-while (thisHubId != NULL)
-    {
-    struct hubConnectStatus *hubStatus = hubFromIdNoAbort(sqlUnsigned(thisHubId->name));
-    if (hubStatus != NULL)
+struct hubConnectStatus *hubStatusList = hubConnectStatusListFromCartAll(cart);
+struct hubConnectStatus *hubStatus = hubStatusList;
+while (hubStatus != NULL)
     {
     if (isEmpty(hubStatus->errorMessage) && fileUrlMatchesHub(fileUrl, hubStatus))
         {
         matchFound = TRUE;
         break;
         }
-        }
-    thisHubId = thisHubId->next;
+    hubStatus = hubStatus->next;
     }
 
 // For native database tracks (not hub or custom tracks), check if fileUrl matches
 // a whitelisted trackDb setting.  Only native tracks are checked here because their
 // settings are admin-configured and trusted.  Hub and custom track settings are
 // user-controlled and could be used for SSRF attacks.
 if (!matchFound)
     {
     char *track = cartOptionalString(cart, "track");
     char *sourceDb = cartOptionalString(cart, "sourceDb"); // for future quickLift use
     if (sourceDb == NULL)
         sourceDb = database;
     if (track != NULL && !isHubTrack(track) && !isCustomTrack(track))
         {
         struct trackDb *tdb = tdbForTrack(sourceDb, track, NULL);