81a04805893ab59c954464ac449abe65da05ac7f hiram Mon Sep 21 16:28:30 2026 -0700 highlight NCBI "reference" assemblies in the search result and hg.conf gated with hgGateway.showRefBadge=on default is off refs #38401 diff --git src/hg/hgGateway/hgGateway.c src/hg/hgGateway/hgGateway.c index 866bf218411..a0d73f49c51 100644 --- src/hg/hgGateway/hgGateway.c +++ src/hg/hgGateway/hgGateway.c @@ -769,43 +769,45 @@ match->label = cloneString(label); return match; } // Genark hub match: struct gHubMatch // description of an genark hub db { struct gHubMatch *next; char *gcAccession; char *hubUrl; char *asmName; char *scientificName; char *commonName; unsigned priority; // for ranking, currently unused + boolean isReference; // TRUE if assemblyList.refSeqCategory == 'reference' }; -static struct gHubMatch *gHubMatchNew(char *acc, char *hubUrl, char *asmName, char *scientificName, char *commonName, unsigned priority) +static struct gHubMatch *gHubMatchNew(char *acc, char *hubUrl, char *asmName, char *scientificName, char *commonName, unsigned priority, boolean isReference) /* Allocate and return a description of an assembly hub db. */ { struct gHubMatch *match; AllocVar(match); match->gcAccession = cloneString(acc); match->hubUrl = cloneString(hubUrl); match->asmName = cloneString(asmName); match->scientificName = cloneString(scientificName); match->commonName = cloneString(commonName); match->priority = priority; +match->isReference = isReference; return match; } static struct hash *unpackHubDbUrlList(struct slName *hubDbUrlList, struct hash **labelHash) /* hubDbUrlList contains strings like "db\tlabel\thubUrl" -- split on tab and return a hash of * hubUrl to one or more dbs. */ { struct hash *hubToDb = hashNew(0); struct hash *dbToLabel = hashNew(0); struct slName *hubDbUrl; for (hubDbUrl = hubDbUrlList; hubDbUrl != NULL; hubDbUrl = hubDbUrl->next) { char *tab = strchr(hubDbUrl->name, '\t'); if (tab) { @@ -1012,30 +1014,31 @@ comBold = genarkBold(savePtr, searchWords[i]); freeMem(savePtr); savePtr = sciBold; sciBold = genarkBold(savePtr, searchWords[i]); freeMem(savePtr); savePtr = gcxBold; gcxBold = genarkBold(savePtr, searchWords[i]); freeMem(savePtr); } jsonWriteObjectStart(jw, NULL); jsonWriteString(jw, "genome", gHubMatch->gcAccession); jsonWriteString(jw, "db", gHubMatch->asmName); jsonWriteString(jw, "hubUrl", gHubMatch->hubUrl); jsonWriteString(jw, "scientificName", gHubMatch->scientificName); + jsonWriteBoolean(jw, "isReference", gHubMatch->isReference); // Add a category label for customized autocomplete-with-categories. jsonWriteString(jw, "category", "UCSC GenArk - bulk-annotated assemblies from NCBI Genbank/RefSeq"); jsonWriteString(jw, "value", gHubMatch->asmName); // Use just the db as label, since shortLabel is included in the category label. jsonWriteStringf(jw, "label", "%s - %s (%s)", comBold, sciBold, gcxBold); jsonWriteObjectEnd(jw); } } /* maximum limit of how many matches to display from genark */ #define GENARK_LIMIT 20 static char *devAlphaHubTxt(char *hubUrl) /* On hgwdev, genome-test and hgwdev sandboxes, GenArk hubs are staged under * alpha.hub.txt instead of hub.txt. On those hosts, swap the trailing @@ -1049,31 +1052,31 @@ static struct gHubMatch *filterGenarkMatches(char *genarkHubUrl, struct genark *matchList) /* Turn the sql results into a struct gHubMatch list */ { struct genark *match; struct gHubMatch *ret = NULL; int c = 0; for (match = matchList; match != NULL; match = match->next) { ++c; // the match contains tab-sep accession, hubUrl, asmName, scientificName, commonName char hubUrl[PATH_LEN+1]; safef(hubUrl, sizeof(hubUrl), "%s/%s", genarkHubUrl, match->hubUrl); char *finalHubUrl = devAlphaHubTxt(hubUrl); - slAddHead(&ret, gHubMatchNew(match->gcAccession, finalHubUrl, match->asmName, match->scientificName, match->commonName, -1)); + slAddHead(&ret, gHubMatchNew(match->gcAccession, finalHubUrl, match->asmName, match->scientificName, match->commonName, -1, FALSE)); freeMem(finalHubUrl); if (c > GENARK_LIMIT) break; } if (ret) slReverse(&ret); return ret; } static struct gHubMatch *filterAssemblyListMatches(struct sqlConnection *conn, struct dbDb *dbDbList, struct dbDbMatch **dbDbMatchList, char *asmListTable, char *term, char *genarkPrefix, boolean wildCard) { struct gHubMatch *ret = NULL; struct dyString *query = dyStringNew(64); /* LIMIT of 100 will allow enough results to include some genArk assemblies */ @@ -1083,31 +1086,38 @@ sqlDyStringPrintf(query, "SELECT * FROM %s WHERE MATCH(name, commonName, scientificName, clade, description, refSeqCategory, versionStatus, assemblyLevel) AGAINST ('%s' IN BOOLEAN MODE) AND browserExists=1 ORDER BY priority LIMIT 100", asmListTable, term); struct sqlResult *sr = sqlGetResult(conn, query->string); dyStringFree(&query); char **row; int c = 0; while ((row = sqlNextRow(sr)) != NULL) { struct assemblyList *el = assemblyListLoadWithNull(row); if (isGenArk(el->name)) { ++c; char genarkUrl[PATH_MAX]; safef(genarkUrl, sizeof(genarkUrl), "%s/%s", genarkPrefix, el->hubUrl); char *finalHubUrl = devAlphaHubTxt(genarkUrl); - slAddHead(&ret, gHubMatchNew(el->name, finalHubUrl, NULL, el->scientificName, el->commonName, *el->priority)); + boolean isReference = FALSE; + if (cfgOptionBooleanDefault("hgGateway.showRefBadge", FALSE) && isNotEmpty(el->refSeqCategory)) + { + char rscBuf[64]; + safecpy(rscBuf, sizeof(rscBuf), el->refSeqCategory); + isReference = sameWord(trimSpaces(rscBuf), "reference"); + } + slAddHead(&ret, gHubMatchNew(el->name, finalHubUrl, NULL, el->scientificName, el->commonName, *el->priority, isReference)); freeMem(finalHubUrl); } else { struct dbDb *dbDb; for (dbDb = dbDbList; dbDb != NULL; dbDb = dbDb->next) { if (sameWord(dbDb->name, el->name)) { // Make uppercase version of target for case-insensitive matching. int targetLen = strlen(el->name); char targetUpcase[targetLen + 1]; safencpy(targetUpcase, sizeof(targetUpcase), el->name, targetLen); touppers(targetUpcase); struct dbDbMatch *extraList = searchDbDb(dbDbList, targetUpcase);