f48fc325d72424177878c4849096c77e06c2d3b0
max
Mon Aug 17 07:34:42 2026 -0700
BLAT results: own track group, Delete-all button, clearer names, refs #38086
Behind hg.conf blatResultsGroup (default off, a release gate):
- BLAT result custom tracks go into their own "BLAT Results" track group
instead of the generic Custom Tracks group.
- That group's header gets a "Delete all" button that removes every BLAT
result track at once, so users are not stuck deleting them one by one.
- Headerless queries are named by query size + the top hit's gene, e.g.
"360bp SOD1", instead of the useless "blat YourSeq"; the date goes in
the longLabel.
hgBlat.c getCustomName naming + blatDateStamp/topHitLocusLabel helpers
hgc.c buildBigPsl tags the results track group=blat
customFactory.c checkGroup accepts the synthetic "blat" group
hgTracks.c synthesize the BLAT Results group; Delete-all button; keep
the per-track delete icon for the new group
hgTracks.js deleteAllBlatTracks()
hgCustom.c hgct_do_delete_blat action (removes all blatResult=on tracks)
hgConfCatalog.py register blatResultsGroup as a release gate
diff --git src/hg/hgTracks/hgTracks.c src/hg/hgTracks/hgTracks.c
index 45051e58b9a..6f695dd6b82 100644
--- src/hg/hgTracks/hgTracks.c
+++ src/hg/hgTracks/hgTracks.c
@@ -7241,30 +7241,47 @@
//
// If there isn't a map group, make one and set the priority so it will be right after custom tracks
// and hub groups.
if (!foundMap)
{
AllocVar(group);
group->name = cloneString("map");
group->label = cloneString("Mapping and Sequencing");
group->defaultPriority = priority;
group->priority = priority;
group->defaultIsClosed = FALSE;
slAddHead(&list, group);
hashAdd(hash, "map", group);
}
+// The "BLAT Results" group holds BLAT-search result custom tracks (group=blat, tagged
+// blatResult=on), keeping them out of the generic Custom Tracks group so they are easy to find and
+// clear as a set. It is synthesized here rather than stored in the grp table; the group header is
+// skipped when it has no tracks (see the group loop that draws the controls). Priority 1.5 places
+// it just after Custom Tracks (priority 1) so BLAT users find their results near the top. Gated by
+// hg.conf blatResultsGroup, the same flag hgBlat/hgc read before tagging tracks with group=blat.
+if (cfgOptionBooleanDefault("blatResultsGroup", FALSE))
+ {
+ AllocVar(group);
+ group->name = cloneString("blat");
+ group->label = cloneString("BLAT Results");
+ group->defaultPriority = group->priority = 1.5;
+ group->defaultIsClosed = FALSE;
+ slAddHead(&list, group);
+ hashAdd(hash, "blat", group);
+ }
+
// The "Visible Tracks" group is now the default top group
struct group *visible = NULL;
AllocVar(visible);
visible->name = "visible";
visible->label = "Visible Tracks";
visible->defaultPriority = priority;
visible->priority = -1;
visible->defaultIsClosed = FALSE;
slAddHead(&list, visible);
hashAdd(hash, "visible", visible);
/* Loop through tracks and fill in their groups.
* If necessary make up an unknown group. */
for (track = *pTrackList; track != NULL; track = track->next)
@@ -8840,31 +8857,31 @@
printTrashIcon("Delete this custom track", "trackDeleteIcon", dataAttrs);
}
static void printQuickLiftDelIcon(struct track *track, char *sourceDb)
/* Trash-can icon next to a track in a quickLift group; clicking it removes
* the track from the quickLift hub. */
{
char dataAttrs[1024];
safef(dataAttrs, sizeof dataAttrs, "data-track='%s' data-sourcedb='%s'", track->track, sourceDb);
printTrashIcon("Remove this track from the QuickLift group", "quickLiftDelIcon", dataAttrs);
}
static void printTrackLink(struct track *track)
/* print a link hgTrackUi with shortLabel and various icons and mouseOvers */
{
-if (sameOk(track->groupName, "user"))
+if (sameOk(track->groupName, "user") || sameOk(track->groupName, "blat"))
printTrackDelIcon(track);
char *quickLiftSourceDb = (track->tdb != NULL) ?
trackDbSetting(track->tdb, "quickLiftDb") : NULL;
/* skip the synthetic "Alignment Differences" track -- it's added at runtime
* by hubConnect, not from the hub file, so removing it from the file is a
* no-op and it would reappear on the next page load. */
if (quickLiftSourceDb != NULL &&
(track->tdb->type == NULL || !startsWith("bigQuickLiftChain", track->tdb->type)))
printQuickLiftDelIcon(track, quickLiftSourceDb);
if (track->hasUi)
{
char *url = trackUrl(track->track, chromName);
char *longLabel = replaceChars(track->longLabel, "\"", """);
@@ -10212,30 +10229,42 @@
if (hub->email)
hPrintf("The authors can be reached at %s", hub->email);
hPrintf("' href='%s' "
"style='color:#FFF; font-size: 13px;' target=_blank>Info", hub->descriptionUrl);
}
hPrintf(" ");
}
}
hPrintf(" ",
group->name);
+ // The BLAT Results group gets a "Delete all" button that removes every BLAT result track
+ // at once, so users are not stuck deleting accumulated results one by one.
+ if (sameString(group->name, "blat"))
+ {
+ safef(idText, sizeof idText, "%s_delAll", group->name);
+ hPrintf(" ", idText);
+ jsOnEventByIdF("click", idText,
+ "if (window.confirm('Delete all %d BLAT result tracks?')) deleteAllBlatTracks();",
+ slCount(group->trackList));
+ }
+
if (hub || group->errMessage)
{
safef(idText, sizeof idText, "%s_%d_disconn", hubName, disconCount);
disconCount++;
hPrintf("\n", idText);
jsOnEventByIdF("click", idText,
"if (window.confirm(\"Disconnect this hub?\\n\\nReconnecting later will require navigating to My Data -> Track Hubs to find it again or re-entering the hub URL.\")) {"
"document.disconnectHubForm.elements['hubId'].value='%s';"
"document.disconnectHubForm.submit();return true;"
"}",
hubName + strlen(hubTrackPrefix));
#ifdef GRAPH_BUTTON_ON_QUICKLIFT