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/hgCustom/hgCustom.c src/hg/hgCustom/hgCustom.c index 160024cb0b9..b236e3f45bc 100644 --- src/hg/hgCustom/hgCustom.c +++ src/hg/hgCustom/hgCustom.c @@ -65,30 +65,31 @@ #define hgCtUpdatedTable CT_UPDATED_TABLE_VAR /* misc */ #define hgCtUpdatedTrack "hgct_updatedTrack" #define hgCtDeletePrefix "hgct_del" #define hgCtRefreshPrefix "hgct_refresh" #define hgCtConfigLines "hgct_configLines" #define hgCtNavDest hgCtNoRemove "navDest" /* commands */ #define hgCtDo hgCt "do_" /* prefix for all commands */ #define hgCtDoAdd hgCtDo "add" #define hgCtDoDelete hgCtDo "delete" #define hgCtDoDeleteSet hgCtDo "delete_set" #define hgCtDoDeleteClr hgCtDo "delete_clr" +#define hgCtDoDeleteBlat hgCtDo "delete_blat" /* delete all BLAT result tracks at once */ #define hgCtDoRefresh hgCtDo "refresh" #define hgCtDoRefreshSet hgCtDo "refresh_set" #define hgCtDoRefreshClr hgCtDo "refresh_clr" #define hgCtDoGenomeBrowser hgCtDo "gb" #define hgCtDoTableBrowser hgCtDo "tb" #ifdef PROGRESS_METER #define hgCtDoProgress hgCtDo "progress" #endif /* Global variables */ struct cart *cart; struct hash *oldVars = NULL; char *excludeVars[] = {"Submit", "submit", "SubmitFile", "ContinueWithWarn", NULL}; char *database = NULL; char *organism = NULL; @@ -1081,30 +1082,47 @@ for (ct = ctList; ct != NULL; ct = ct->next) { char var[256]; safef(var, sizeof var, "%s_%s", hgCtDeletePrefix, ct->tdb->track); if (!cartUsualBoolean(cart, var, FALSE)) continue; /* myVariants tracks are backed by a per-user SQL table, not the CT * file, so dropping them from ctList alone isn't enough -- the next * page load regenerates the CT entry from the database. Delegate * the type-specific cleanup. */ myVariantsHandleCtRemoval(ct, cart, database); slRemoveEl(&ctList, ct); } } +void doDeleteBlatCustom() +/* remove all BLAT result custom tracks at once (those tagged blatResult=on). This backs the + * "Delete all" button in hgTracks' BLAT Results group, so users are not left removing accumulated + * BLAT results one at a time. */ +{ +struct customTrack *ct, *next; +for (ct = ctList; ct != NULL; ct = next) + { + next = ct->next; + if (ct->tdb != NULL && sameOk(trackDbSetting(ct->tdb, "blatResult"), "on")) + { + myVariantsHandleCtRemoval(ct, cart, database); + slRemoveEl(&ctList, ct); + } + } +} + void doRefreshCustom(char **warnMsg) /* reparse custom tracks from URLs based on cart variables */ { struct customTrack *ct; struct customTrack *replacedCts = NULL; struct customTrack *refreshCts = NULL; for (ct = ctList; ct != NULL; ct = ct->next) { char var[256]; safef(var, sizeof var, "%s_%s", hgCtRefreshPrefix, ct->tdb->track); if (cartUsualBoolean(cart, var, FALSE)) { struct customTrack *nextCt = NULL, *urlCt = NULL; struct customTrack *urlCts = @@ -1477,30 +1495,35 @@ if ((selectedTable= cartOptionalString(cart, hgCtUpdatedTable)) != NULL) { ct = ctFromList(ctList, selectedTable); doUpdateCustom(ct, err, warnOnly); } else doAddCustom(err, warnOnly); cartRemovePrefix(cart, hgCt); return; } if (cartVarExists(cart, hgCtDoDelete)) { doDeleteCustom(); ctUpdated = TRUE; } + if (cartVarExists(cart, hgCtDoDeleteBlat)) + { + doDeleteBlatCustom(); + ctUpdated = TRUE; + } if (cartVarExists(cart, hgCtDoRefresh)) { doRefreshCustom(&warnMsg); addWarning(dsWarn, warnMsg); ctUpdated = TRUE; } if (ctUpdated || ctConfigUpdate(ctFileName)) { customTracksSaveCart(database, cart, ctList); /* refresh ctList again to pickup remote resource error state */ warnOnly=FALSE; struct errCatch *catch = errCatchNew(); if (errCatchStart(catch)) ctList = customTracksParseCartDetailed(database, cart, &browserLines, &ctFileName, @@ -1509,31 +1532,31 @@ if (catch->gotError) { addWarning(dsWarn, err); addWarning(dsWarn, catch->message->string); } errCatchFree(&catch); } warnMsg = dyStringCannibalize(&dsWarn); if (measureTiming) { long lastTime = clock1000(); loadTime = lastTime - thisTime; } - if (ctList || cartVarExists(cart, hgCtDoDelete)) + if (ctList || cartVarExists(cart, hgCtDoDelete) || cartVarExists(cart, hgCtDoDeleteBlat)) doManageCustom(warnMsg); else doAddCustom(warnMsg, warnOnly); } cartRemovePrefix(cart, hgCt); cartRemove(cart, CT_CUSTOM_TEXT_VAR); } int main(int argc, char *argv[]) /* Process command line. */ { long enteredMainTime = clock1000(); issueBotWarning = earlyBotCheck(enteredMainTime, "hgCustom", delayFraction, 0, 0, "html"); htmlPushEarlyHandlers();