c9655cda984d9a119d0c4ee37505392fa853a224 max Thu Aug 6 05:47:02 2026 -0700 Move the orphaned range-filter warning from hgTrackUi to hubCheck, refs #37927 Per Brian's review comment: a new warning on the track config page makes hubs that used to work look broken to whoever opens them, and the browser is the wrong place to nag about it. Revert the hui.c warning and do the check in hubCheck instead, where the hub author is the one reading the output. The check now looks only at settings declared on the stanza itself, so an orphaned filterByRange on a composite parent is reported once rather than repeated for every subtrack. The filter.<field> lookup still walks up the parent chain, so a subtrack that inherits its default range stays quiet. diff --git src/hg/utils/hubCheck/hubCheck.c src/hg/utils/hubCheck/hubCheck.c index 76a5e2ad827..62a42691728 100644 --- src/hg/utils/hubCheck/hubCheck.c +++ src/hg/utils/hubCheck/hubCheck.c @@ -925,30 +925,68 @@ if (i == 0) settingName = VIEWLIMITS; if (i == 1) settingName = VIEWLIMITSMAX; if (i == 2) settingName = DEFAULTVIEWLIMITS; char *setting = trackDbSetting(tdb, settingName); if (setting) { parseColonRange(tdb, settingName, setting); } } } +void checkOrphanedRangeFilters(struct trackDb *tdb) +/* A numeric filter is only DISCOVERED from a filter.<field> (or <field>Filter) + * setting -- see FILTER_NUMBER_WILDCARD and tdbGetTrackNumFilters(). A + * filterByRange.<field> or filterLimits.<field> with no matching filter.<field> + * is silently ignored and its control never appears, which is an easy and + * confusing mistake to make. Warn so the hub developer sees why a filter they + * configured did not show up. Only the settings on this stanza are inspected, so + * an inherited setting is reported once, on the stanza that declares it. */ +{ +struct slName *rangeSettings = slCat(trackDbLocalSettingsWildMatch(tdb, "filterByRange.*"), + trackDbLocalSettingsWildMatch(tdb, "filterLimits.*")); +struct hash *seen = hashNew(0); +struct slName *s; +for (s = rangeSettings; s != NULL; s = s->next) + { + char *field = strchr(s->name, '.'); + if (field == NULL) + continue; + field++; // skip past the '.' + if (hashLookup(seen, field) != NULL) + continue; + hashAdd(seen, field, NULL); + char setting[512]; + safef(setting, sizeof setting, "filter.%s", field); + if (trackDbSettingClosestToHome(tdb, setting) != NULL) + continue; + safef(setting, sizeof setting, "%sFilter", field); + if (trackDbSettingClosestToHome(tdb, setting) != NULL) + continue; + warn("track \"%s\" has a filterByRange/filterLimits setting for field '%s' " + "but no 'filter.%s' (the default range), so this filter is not shown. " + "Add 'filter.%s min:max' to enable it.", + trackHubSkipHubName(tdb->track), field, field, field); + } +hashFree(&seen); +slFreeList(&rangeSettings); +} + int hubCheckTrack(struct trackHub *hub, struct trackHubGenome *genome, struct trackDb *tdb, struct trackHubCheckOptions *options, struct dyString *errors) /* Check track settings and optionally, files */ { int retVal = 0; int trackDbErrorCount = 0; if (options->checkSettings && options->settings) { //verbose(3, "Found %d settings to check to spec\n", slCount(settings)); verbose(3, "Checking track: %s\n", tdb->shortLabel); verbose(3, "Found %d settings to check to spec\n", hashNumEntries(tdb->settingsHash)); struct hashEl *hel; struct hashCookie cookie = hashFirst(tdb->settingsHash); while ((hel = hashNext(&cookie)) != NULL) @@ -1009,30 +1047,32 @@ // check that type line is syntactically correct regardless of // if we actually want to check the data file itself boolean foundTypeError = checkTypeLine(genome, tdb, errors, options); retVal |= foundTypeError; // No point in checking the data file if the type setting is incorrect, // since hubCheckBigDataUrl will error out early with a less clear message // if the type line is messed up. This has the added benefit of providing // consistent messaging on command line interface vs web interface if (!foundTypeError && options->checkFiles) hubCheckBigDataUrl(hub, genome, tdb); checkViewLimitsSettings(tdb); + checkOrphanedRangeFilters(tdb); + if (!sameString(tdb->track, "cytoBandIdeo")) { trackHubAddDescription(genome->trackDbFile, tdb); if (!tdb->html) warn("warning: missing description page for track. Add 'html %s.html' line to the '%s' track stanza. ", tdb->track, tdb->track); } if (!trackIsContainer && sameString(trackDbRequiredSetting(tdb, "type"), "bigWig")) { char *autoScaleSetting = trackDbLocalSetting(tdb, "autoScale"); if (autoScaleSetting && !sameString(autoScaleSetting, "off") && !sameString(autoScaleSetting, "on")) { errAbort("track \"%s\" uses 'autoScale %s', but individual bigWig tracks only accept " "'autoScale on' or 'autoScale off'. If you're trying to set 'autoScale group', "