28b0357b2f17050e591d3d21e3fe2511e2ad0b55
max
  Mon May 4 05:50:49 2026 -0700
hgTrackUi: address #37426 QA feedback

- Drop the unconditional bottom Submit button (introduced in 33d86ed) — it
duplicated the existing top Submit on composites like refSeqComposite.
Gate it on tdbIsSuperTrack so only superTracks get the bottom Submit
(the case the original commit was meant to address).
- Render the "Reset to defaults" link on superTrack pages too. Wire up the
cart-clear path: superTrack children live in tdb->children (slRef), not
tdb->subtracks, so cartRemoveAllForTdbAndChildren wouldn't reach them —
walk children explicitly.
- Filters heading: "Filters " → "Filters:" (matches the "Apply visibility:" /
"Show or hide ...:" style elsewhere on the page).
- Reword the Filters info tooltip per Gerardo's QA suggestion.

refs #37426

diff --git src/hg/hgTrackUi/hgTrackUi.c src/hg/hgTrackUi/hgTrackUi.c
index d82c9429a94..3feb32b6d2d 100644
--- src/hg/hgTrackUi/hgTrackUi.c
+++ src/hg/hgTrackUi/hgTrackUi.c
@@ -2930,35 +2930,34 @@
   "}"
   "});");
 // * Hide all subtrack dropdowns from the user. They are used so the CGI arguments
 // are sent to hgTracks, but are not necessary as UI elements anymore
 jsInline("$('#superTrackTable .vizSelect').hide();");
 
 // --- Supertrack-level filters ---
 // If the supertrack's trackDb declares any filter.*, filterValues.*,
 // filterByRange.*, etc. settings, render the standard filter UI here.
 // The cart variables are stored under the supertrack's name
 // (e.g. "lrSv.filter.svLen.min"). Subtracks inherit these values via
 // cartOptionalStringClosestToHome() during hgTracks rendering; a cart
 // value set on a subtrack always overrides the supertrack's.
 if (bedHasFilters(superTdb))
     {
-    puts("<h3 style='margin-top:1em'>Filters ");
-    printInfoIcon("Values set here are inherited by every subtrack in this "
-                  "container. Any filter set on an individual subtrack's "
-                  "Track Settings page overrides the value set here for that "
-                  "subtrack only.");
+    puts("<h3 style='margin-top:1em'>Filters: ");
+    printInfoIcon("Filter values set here apply to every track in this "
+                  "container. A filter set directly on an individual track "
+                  "overrides the value here for that track only.");
     puts("</h3>");
     // Pass title=NULL so scoreCfgUi does not emit its "<p><B>title</B>"
     // banner. The container <h3> above is already the section label.
     scoreCfgUi(database, cart, superTdb, superTdb->track,
                NULL, 1000, /*boxed=*/FALSE);
     }
 }
 
 #ifdef USE_HAL
 static void cfgHalSnake(struct trackDb *tdb, char *name)
 {
 boolean parentLevel = isNameAtParentLevel(tdb, name);
 if (parentLevel)
     return;
 char *fileName = trackDbSetting(tdb, "bigDataUrl");
@@ -3777,36 +3776,50 @@
               tdbParent = tdbParent->parent )
             ; // Get the first parent that has html
         if (tdbParent != NULL && tdbParent->html != NULL && tdbParent->html[0])
             {
             printf("<h2 style='color:%s'>Retrieved from %s Track...</h2>\n",
                    COLOR_DARKGREEN,tdbParent->shortLabel);
             printRelatedTracks(database,trackHash,tdb,cart);
             puts(tdbParent->html);
             }
         else
             printf("<h2>No description found for: %s.</h2>",tdbParent?tdbParent->track:tdb->track);
         }
     cartRemove(cart,"descriptionOnly"); // This is a once only request and should be deleted
     return;
     }
-if (tdbIsContainer(tdb))
+if (tdbIsContainer(tdb) || tdbIsSuperTrack(tdb))
     {
     safef(setting,sizeof(setting),"%s.%s",tdb->track,RESET_TO_DEFAULTS);
     // NOTE: if you want track vis to not be reset, move to after vis dropdown
     if (1 == cartUsualInt(cart, setting, 0))
+        {
+        if (tdbIsSuperTrack(tdb))
+            {
+            // SuperTrack children live in tdb->children (slRef list), not in
+            // the subtracks tree that cartRemoveAllForTdbAndChildren walks.
+            // Clear the supertrack's own cart vars (filters, visibility) and
+            // each child's vars by hand.
+            cartRemoveAllForTdb(cart, tdb);
+            struct slRef *childRef;
+            for (childRef = tdb->children; childRef != NULL; childRef = childRef->next)
+                cartRemoveAllForTdb(cart, (struct trackDb *)childRef->val);
+            }
+        else
             cartRemoveAllForTdbAndChildren(cart,tdb);
+        }
     else if (!ajax) // Overkill on !ajax, because ajax shouldn't be called for a composite
         cartTdbTreeReshapeIfNeeded(cart,tdb);
     }
 
 /* track configuration form */
 
 printf("<FORM ACTION=\"%s?hgsid=%s&db=%s\" NAME=\""MAIN_FORM"\" METHOD=%s>\n\n",
        hgTracksName(), cartSessionId(cart), database, cartUsualString(cart, "formMethod", "POST"));
 cartSaveSession(cart);
 if (sameWord(tdb->track,"ensGene"))
     {
     char longLabel[256];
     struct trackVersion *trackVersion = getTrackVersion(database, tdb->track);
     if ((trackVersion != NULL) && !isEmpty(trackVersion->version))
         {
@@ -3951,31 +3964,31 @@
             hTvDropDownClassVisOnlyAndExtra(tdb->track,vis,canPack,"normalText visDD",
                                             trackDbSetting(tdb, "onlyVisibility"),NULL);
         }
 
     if (!ajax)
         {
         printf("&nbsp;");
         cgiMakeButton("Submit", "Submit");
         // Offer cancel button always?    // composites and multiTracks (not standAlones or supers)
         if (tdbIsContainer(tdb))
             {
             printf("&nbsp;");
             cgiMakeOnClickButton("htui_cancel", "window.history.back();","Cancel");
             }
 
-        if (tdbIsComposite(tdb))
+        if (tdbIsComposite(tdb) || tdbIsSuperTrack(tdb))
 	    {
             printf("\n&nbsp;&nbsp;<a href='#' id='htui_reset'>Reset to defaults</a>\n");
 	    jsOnEventByIdF("click", "htui_reset",
                    "setVarAndPostForm('%s','1','mainForm'); return false;", setting);
 	    }
         if ( isCustomComposite(tdb))
             {
             printf("\n&nbsp;&nbsp;<a href='%s' >Go to Track Collection Builder</a>\n", hgCollectionName());
             }
 	/* Offer to dupe the non-containery tracks including composite and supertrack elements */
 	if (tdbIsDupable(tdb))
 	    {
 	    printf("\n&nbsp;&nbsp;<a href='%s?%s=%s&c=%s&g=%s&hgTrackUi_op=dupe' >Duplicate track</a>\n", 
 		hgTrackUiName(), cartSessionVarName(), cartSessionId(cart),
 		chromosome, cgiEncode(tdb->track));
@@ -4061,31 +4074,33 @@
 
 // Decorator UI
 struct slName *decoratorSettings = trackDbSettingsWildMatch(tdb, "decorator.*");
 if (decoratorSettings)
     {
     char *browserVersion;
     if (btIE == cgiClientBrowser(&browserVersion, NULL, NULL) && *browserVersion < '8')
         htmlHorizontalLine();
     else
         printf("<HR ALIGN='bottom' style='position:relative; top:1em;'>");
     decoratorUi(tdb, cart, decoratorSettings);
     }
 
 // Repeat the Submit button near the bottom of the form so that users do not
 // have to scroll back up to the top after tweaking filters on a long page.
-if (!ajax)
+// Only superTracks need this: composites and regular tracks already render
+// their own Submit button at the bottom of their controls.
+if (!ajax && tdbIsSuperTrack(tdb))
     {
     puts("<p style='margin-top:1em;'>");
     cgiMakeButton("Submit", "Submit");
     puts("</p>");
     }
 
 puts("</FORM>");
 
 if (ajax)
     return;
 
 if (ct)
     {
     /* hidden form for custom tracks CGI */
     printf("<FORM ACTION='%s' NAME='customTrackForm'>", hgCustomName());