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/js/hgTracks.js src/hg/js/hgTracks.js
index b6d7d116e9c..86ee723677b 100644
--- src/hg/js/hgTracks.js
+++ src/hg/js/hgTracks.js
@@ -5545,30 +5545,43 @@
 }
 
 function deleteCustomTrack (trackName) {
     /* Tell hgCustom to delete the given custom track. Shared by the trash icon
      * and the right-click context menu so there is only one deletion code path. */
     // https://genome.ucsc.edu/cgi-bin/hgCustom?hgsid=1645697744_i0Yp2Di71NytSDdb6r0vUbupIvKO&hgct_do_delete=delete&hgct_del_ct_UserTrack_3545=on
     var hgsid = getHgsid();
     var url = 'hgCustom?hgsid='+hgsid+'&hgct_do_delete=delete&hgct_del_'+trackName+'=on';
     var xhttp = new XMLHttpRequest();
     // this cannot be asyncronous, as users can click quickly here and the hgCustom calls above cannot run in parallel
     // since we store custom tracks as a text file, not mysql tables
     xhttp.open("GET", url, false);
     xhttp.send();
 }
 
+function deleteAllBlatTracks () {
+    /* Tell hgCustom to delete every BLAT result custom track at once (those tagged blatResult=on),
+     * then reload so the BLAT Results group updates. Triggered by the group's "Delete all" button. */
+    var hgsid = getHgsid();
+    var url = 'hgCustom?hgsid='+hgsid+'&hgct_do_delete_blat=1';
+    var xhttp = new XMLHttpRequest();
+    // synchronous, for the same reason as deleteCustomTrack: custom tracks live in a text file, not
+    // in parallel-safe mysql rows
+    xhttp.open("GET", url, false);
+    xhttp.send();
+    window.location.reload();
+}
+
 function onTrackDelIconClick (ev) {
     /* delete custom track if user clicks its trash icon */
     var divEl = ev.target.closest("div"); // must use .closest(), as user can click on either the SVG or the DIV space.
     var trackName = divEl.getAttribute("data-track");
     deleteCustomTrack(trackName);
     // if the track is currently drawn, also remove it from the image and update
     // hgTracks.trackDb/cart, the same cleanup the right-click delete does. hideTracks()
     // assumes the track is in hgTracks.trackDb, so only call it when it is.
     if (hgTracks.trackDb && hgTracks.trackDb[trackName])
         rightClick.hideTracks([trackName]);
     divEl.closest("td").remove();
 }
 
 function onQuickLiftDelIconClick (ev) {
     /* Remove this track's stanza from the quickLift hub in trash, and