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(" "); cgiMakeButton("Submit", "Submit"); // Offer cancel button always? // composites and multiTracks (not standAlones or supers) if (tdbIsContainer(tdb)) { printf(" "); cgiMakeOnClickButton("htui_cancel", "window.history.back();","Cancel"); } - if (tdbIsComposite(tdb)) + if (tdbIsComposite(tdb) || tdbIsSuperTrack(tdb)) { printf("\n <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 <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 <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());