47ea57080b515e5dad5f658c58feb8944a7e7d61 chmalee Thu Jan 29 15:30:26 2026 -0800 Replace clade/assembly dropdowns with a search bar on most CGIs. Add a recents list to hgGateway and to the species bar and to the 'Genomes' dropdown menu. Track recently selected species in localStorage. Add toGenome and fromGenome arguemnts to hubApi/liftOver in order to find appropriate liftover assemblies, refs #36232 diff --git src/hg/hubApi/liftOver.c src/hg/hubApi/liftOver.c index 7f0b6a0429a..1630e9945cc 100644 --- src/hg/hubApi/liftOver.c +++ src/hg/hubApi/liftOver.c @@ -1,25 +1,26 @@ /* liftOver functions */ #include "dataApi.h" #include "hgFind.h" #include "cartTrackDb.h" #include "cartJson.h" #include "genark.h" #include "asmAlias.h" #include "assemblyList.h" #include "liftOver.h" +#include "liftOverChain.h" #include "net.h" #include "mailViaPipe.h" /**** SHOULD BE IN LIBRARY - code from hgConvert.c ******/ static long chainTotalBlockSize(struct chain *chain) /* Return sum of sizes of all blocks in chain */ { struct cBlock *block; long total = 0; for (block = chain->blockList; block != NULL; block = block->next) total += block->tEnd - block->tStart; return total; } /**** SHOULD BE IN LIBRARY - code from hgConvert.c ******/ @@ -57,81 +58,86 @@ 100.0 * blockSize / origSize, 100.0 * (chain->tEnd - chain->tStart) / origSize); jsonWriteListStart(jw, NULL); jsonWriteString(jw, NULL, toDb); jsonWriteString(jw, NULL, position); jsonWriteString(jw, NULL, coverage); jsonWriteListEnd(jw); } jsonWriteListEnd(jw); apiFinishOutput(0, NULL, jw); } static void listExisting() /* output the fromDb,toDb from liftOverChain.hgcentral SQL table */ { -long long itemCount = 0; char *filter = cgiOptionalString(argFilter); char *fromDb = cgiOptionalString(argFromGenome); char *toDb = cgiOptionalString(argToGenome); struct sqlConnection *conn = hConnectCentral(); char *tableName = cloneString(liftOverChainTable()); struct dyString *query = newDyString(0); sqlDyStringPrintf(query, "SELECT count(*) FROM %s", tableName); long long totalRows = sqlQuickLongLong(conn, dyStringContents(query)); dyStringClear(query); if (isNotEmpty(fromDb) || isNotEmpty(toDb)) { - sqlDyStringPrintf(query, "SELECT fromDb,toDb FROM %s WHERE ", tableName); + sqlDyStringPrintf(query, "SELECT * FROM %s WHERE ", tableName); if (isNotEmpty(fromDb)) sqlDyStringPrintf(query, "LOWER(fromDb) = LOWER('%s') %s ", fromDb, isNotEmpty(toDb) ? "AND" : ""); if (isNotEmpty(toDb)) sqlDyStringPrintf(query, "LOWER(toDb) = LOWER('%s') ", toDb); - sqlDyStringPrintf(query, "LIMIT %d;", maxItemsOutput); } else if (isNotEmpty(filter)) { - sqlDyStringPrintf(query, "SELECT fromDb,toDb FROM %s WHERE LOWER(fromDb) = LOWER('%s') OR LOWER(toDb) = LOWER('%s') LIMIT %d;", tableName, filter, filter, maxItemsOutput); + sqlDyStringPrintf(query, "SELECT * FROM %s WHERE LOWER(fromDb) = LOWER('%s') OR LOWER(toDb) = LOWER('%s')", tableName, filter, filter); } else { - sqlDyStringPrintf(query, "SELECT fromDb,toDb FROM %s LIMIT %d", tableName, maxItemsOutput); + sqlDyStringPrintf(query, "SELECT * FROM %s", tableName); } +sqlDyStringPrintf(query, " LIMIT %d;", maxItemsOutput); char *dataTime = sqlTableUpdate(conn, tableName); time_t dataTimeStamp = sqlDateToUnixTime(dataTime); replaceChar(dataTime, ' ', 'T'); /* ISO 8601 */ struct jsonWrite *jw = apiStartOutput(); jsonWriteString(jw, "dataTime", dataTime); jsonWriteNumber(jw, "dataTimeStamp", (long long)dataTimeStamp); jsonWriteListStart(jw, "existingLiftOvers"); -struct sqlResult *sr = sqlGetResult(conn, dyStringCannibalize(&query)); -char **row; -while ((row = sqlNextRow(sr)) != NULL) +struct liftOverChain *chain, *chainList = liftOverChainLoadByQuery(conn, dyStringCannibalize(&query)); +for (chain = chainList; chain != NULL; chain = chain->next) { - ++itemCount; - jsonWriteListStart(jw, NULL); - jsonWriteString(jw, NULL, row[0]); - jsonWriteString(jw, NULL, row[1]); - jsonWriteListEnd(jw); + jsonWriteObjectStart(jw, NULL); + jsonWriteString(jw, "fromDb", chain->fromDb); + jsonWriteString(jw, "toDb", chain->toDb); + jsonWriteString(jw, "path", chain->path); + jsonWriteDouble(jw, "minMatch", chain->minMatch); + jsonWriteNumber(jw, "minChainT", chain->minChainT); + jsonWriteNumber(jw, "minSizeQ", chain->minSizeQ); + jsonWriteString(jw, "multiple", chain->multiple); + jsonWriteDouble(jw, "minBlocks", chain->minBlocks); + jsonWriteString(jw, "fudgeThick", chain->fudgeThick); + jsonWriteObjectEnd(jw); } jsonWriteListEnd(jw); jsonWriteNumber(jw, "totalLiftOvers", totalRows); -jsonWriteNumber(jw, "itemsReturned", itemCount); +jsonWriteNumber(jw, "itemsReturned", slCount(chainList)); +liftOverChainFreeList(&chainList); apiFinishOutput(0, NULL, jw); hDisconnectCentral(&conn); } /**** SHOULD BE IN LIBRARY - code from hgConvert.c ******/ static char *skipWord(char *fw) /* skips over current word to start of next. * Error for this not to exist. */ { char *s; s = skipToSpaces(fw); if (s == NULL) errAbort("Expecting two words in .ra file line %s\n", fw); s = skipLeadingSpaces(s);