66ea6cb4eaf2036e464be55b295765ed5105a0fb max Wed Apr 22 09:42:25 2026 -0700 hgTrackUi/hui: render filter UI on supertrack configuration pages Supertracks (group of tracks with superTrack on, no data of their own) previously had no way to expose a shared filter: their trackDb stanza can declare filter.* / filterByRange.* / filterValues.*, but those settings were never drawn on the supertrack's hgTrackUi page. So users had to open each subtrack's own configuration page and set the same filter there, and the "lrSv.filter.svLen" cart namespace went unused. This change wires that up: - hgTrackUi.c (superTrackUi): after listing the subtracks, if the supertrack tdb declares any filter.* settings call scoreCfgUi() to render the standard filter UI. Cart variables land under the supertrack's own name (e.g. "lrSv.filter.svLen.min"), and subtracks already inherit them through cartOptionalStringClosestToHome() walking tdb->parent. Subtrack-level values continue to override. - hui.c: - buildFilterBy() / filterByValues(): tolerate a NULL autoSql object, so supertracks (which have no data table) don't errAbort when they declare filterValues.* of virtual aggregated fields. Missing-field errAbort still fires in the normal subtrack case. - scoreCfgUi() / cfgByCfgType(): when called with title == NULL (the supertrack filter path), suppress the default "<p>" separator and the "<BR>" between the title bar and the filter block; the caller renders its own section heading. - asForTdb(): handle conn == NULL by returning NULL rather than crashing, since supertrack filter rendering has no associated sqlConnection. refs #37426 diff --git src/hg/hgTrackUi/hgTrackUi.c src/hg/hgTrackUi/hgTrackUi.c index d4d3ac60db7..42c89a3ce70 100644 --- src/hg/hgTrackUi/hgTrackUi.c +++ src/hg/hgTrackUi/hgTrackUi.c @@ -2918,30 +2918,51 @@ "$(this).next().children().removeClass('seg-active');" "let labelToFind = capitalizeFirstLetter($(this).val());" "$(this).next().find('button').filter(function() { return $(this).text().trim() === labelToFind; }).addClass('seg-active');" "});"); // * Grey out the superTrack dropdown when manually set to hide jsInline("$('.superDropdown').on('change', function() {" "if ($(this).val() === 'hide') {" "$(this).removeClass('normalText').addClass('hiddenText');" "} else {" "$(this).removeClass('hiddenText').addClass('normalText');" "}" "});"); // * 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>"); + // 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"); if (fileName == NULL) return; char *errString; int handle = halOpenLOD(fileName, &errString); if (handle < 0) errAbort("can't open HAL file: %s", fileName);