5b8fdca0d6014f4b2f363724ee91f096ef62eae5 chmalee Thu Sep 30 12:21:57 2021 -0700 Get hub track selection box and hgTrackUi links working on track search diff --git src/hg/hgTracks/searchTracks.c src/hg/hgTracks/searchTracks.c index 8564780..1e5a2b3 100644 --- src/hg/hgTracks/searchTracks.c +++ src/hg/hgTracks/searchTracks.c @@ -34,30 +34,35 @@ #define TRACK_SEARCH_FORM "trackSearch" #define SEARCH_RESULTS_FORM "searchResults" #define TRACK_SEARCH_CURRENT_TAB "tsCurTab" #define TRACK_SEARCH_SIMPLE "tsSimple" #define TRACK_SEARCH_ON_NAME "tsName" #define TRACK_SEARCH_ON_TYPE "tsType" #define TRACK_SEARCH_ON_GROUP "tsGroup" #define TRACK_SEARCH_ON_DESCR "tsDescr" #define TRACK_SEARCH_SORT "tsSort" #define TRACK_SEARCH_ON_HUBS "tsIncludePublicHubs" // the list of found tracks struct slRef *tracks = NULL; +// for advanced search only: +// associates hub id's to hub urls that have search results, +// used to get huburls onto hgTrackUi links +struct hash *hubIdsToUrls = NULL; + static int gCmpGroup(const void *va, const void *vb) /* Compare groups based on label. */ { const struct group *a = *((struct group **)va); const struct group *b = *((struct group **)vb); return strcmp(a->label, b->label); } // Would like to do a radio button choice ofsorts enum sortBy { sbRelevance=0, sbAbc =1, sbHierarchy=2, }; @@ -296,71 +301,75 @@ pfd->done = TRUE; if (measureTiming) { pfd->searchTime = clock1000() - startTime;; measureTime("Finished finding tracks for hub '%s': ", pfd->hubName); } slRemoveEl(&pfdRunning, pfd); slAddHead(&pfdDone, pfd); pthread_mutex_unlock(&pfdMutex); } errCatchEnd(errCatch); //always return NULL for pthread_create() return NULL; } -static void hubSearchHashToPfdList(struct hash *searchResultsHash, struct hash *hubLookup, - struct sqlConnection *conn) +static void hubSearchHashToPfdList(char *descSearch, struct hash *searchResultsHash, + struct hash *hubLookup, struct sqlConnection *conn) /* getHubSearchResults() returned a hash of search hits to various hubs, convert that * into something we can work on in parallel */ { struct hubSearchTracks *ret = NULL; struct hashCookie cookie = hashFirst(searchResultsHash); struct hash *hubUrlsToTrackList = hashNew(0); struct hashEl *hel = NULL; struct dyString *trackName = dyStringNew(0); struct slName *connectedHubs = hubConnectHubsInCart(cart); while ((hel = hashNext(&cookie)) != NULL) { struct hubSearchText *hst = (struct hubSearchText *)hel->val; struct hubEntry *hubInfo = (struct hubEntry *) hashFindVal(hubLookup, hst->hubUrl); if (isNotEmpty(hubInfo->errorMessage)) continue; - // if we were already checking out this hub, then it's search hits + // if we were already connected to this hub, then it's search hits // were already taken care of by the regular search code char hubId[256]; safef(hubId, sizeof(hubId), "%d", hubInfo->id); if (slNameInList(connectedHubs, hubId)) continue; struct hubConnectStatus *hub = hubConnectStatusForId(conn, hubInfo->id); // the hubSearchText contains multiple entries per lookup in order to form // the hgHubConnect UI. We only need one type of hit here: struct hubSearchTracks *found = hashFindVal(hubUrlsToTrackList, hst->hubUrl); for (; hst != NULL; hst = hst->next) { // don't add results for matches to the hub descriptionUrl, only to track names/descs if (isNotEmpty(hst->track) && hst->textLength != hubSearchTextMeta) { + // hst->textLength=hubSearchTextLong denotes hits to track description + if (isNotEmpty(descSearch) && hst->textLength != hubSearchTextLong) + continue; if (!found) { AllocVar(found); found->hubUrl = hst->hubUrl; found->searchedTracks = NULL; found->hub = hub; found->hubId = hubInfo->id; slAddHead(&ret, found); hashAdd(hubUrlsToTrackList, hst->hubUrl, found); + hashAdd(hubIdsToUrls, hubId, hst->hubUrl); } dyStringPrintf(trackName, "%s%d_%s", hubTrackPrefix, hubInfo->id, hst->track); slNameStore(&found->searchedTracks, cloneString(trackName->string)); dyStringClear(trackName); } } } struct hubSearchTracks *t; for (t = ret; t != NULL; t = t->next) { struct paraFetchData *pfd; AllocVar(pfd); pfd->hubName = t->hubUrl; pfd->hst = t; slAddHead(&pfdList, pfd); @@ -441,60 +450,62 @@ { // Should we warn or something that results are still waiting? As of now // just silently return instead, and note that no unconnected hub data // will show up (we get connected hub results for free because of // trackDbCaching) if (measureTiming) measureTime("Timed out searching hubs"); } if (lockStatus == 0) pthread_mutex_unlock(&pfdMutex); } void addHubSearchResults(struct slName *nameList, char *descSearch) /* add public hubs to the track list */ { -// set to something large so we always use the udc cache struct sqlConnection *conn = hConnectCentral(); char *hubSearchTableName = hubSearchTextTableName(); char *publicTable = cfgOptionEnvDefault("HGDB_HUB_PUBLIC_TABLE", hubPublicTableConfVariable, defaultHubPublicTableName); char *statusTable = cfgOptionEnvDefault("HGDB_HUB_STATUS_TABLE", hubStatusTableConfVariable, defaultHubStatusTableName); struct dyString *extra = dyStringNew(0); if (nameList) { struct slName *tmp = NULL; + char escapedInput[512]; for (tmp = nameList; tmp != NULL; tmp = tmp->next) { - dyStringPrintf(extra, "label like '%%%s%%'", tmp->name); + // escape user input manually: + sqlSafefFrag(escapedInput, sizeof(escapedInput), "%s", tmp->name); + dyStringPrintf(extra, "label like '%%%s%%'", escapedInput); if (tmp->next) dyStringPrintf(extra, " and "); } } if (sqlTableExists(conn, hubSearchTableName)) { struct hash *searchResultsHash = hashNew(0); struct hash *pHash = hashNew(0); struct slName *hubsToPrint = NULL; addPublicHubsToHubStatus(cart, conn, publicTable, statusTable); struct hash *hubLookup = buildPublicLookupHash(conn, publicTable, statusTable, &pHash); char *db = cloneString(trackHubSkipHubName(database)); tolowers(db); - getHubSearchResults(conn, hubSearchTableName, descSearch, descSearch != NULL, db, hubLookup, &searchResultsHash, &hubsToPrint, extra->string); - hubSearchHashToPfdList(searchResultsHash, hubLookup, conn); + getHubSearchResults(conn, hubSearchTableName, descSearch, isNotEmpty(descSearch), db, hubLookup, &searchResultsHash, &hubsToPrint, dyStringCannibalize(&extra)); + hubSearchHashToPfdList(descSearch, searchResultsHash, hubLookup, conn); if (measureTiming) measureTime("after querying hubSearchText table and ready to start threads"); int ptMax = atoi(cfgOptionDefault("parallelFetch.threads", "20")); int pfdListCount = 0, pt; if (ptMax > 0) { pfdListCount = slCount(pfdList); pthread_t *threads = NULL; ptMax = min(ptMax, pfdListCount); if (ptMax > 0) { AllocArray(threads, ptMax); for (pt = 0; pt < ptMax; pt++) { int rc = pthread_create(&threads[pt], NULL, addUnconnectedHubSearchResults, &threads[pt]); @@ -813,115 +824,164 @@ cgiMakeOnEventRadioButtonWithClass(TRACK_SEARCH_SORT, "1", (sortBy == sbAbc), NULL,"click", "findTracks.sortNow(this);"); hPrintf("Alphabetically"); cgiMakeOnEventRadioButtonWithClass(TRACK_SEARCH_SORT, "2", (sortBy == sbHierarchy), NULL,"click", "findTracks.sortNow(this);"); hPrintf("by Hierarchy \n"); } hPrintf("\n"); // Set up json for js functionality struct jsonElement *jsonTdbVars = newJsonObject(newHash(8)); int trackCount=0; boolean containerTrackCount = 0; struct slRef *ptr; + struct slName *connectedHubIds = hubConnectHubsInCart(cart); while((ptr = slPopHead(&tracks))) { if (++trackCount > MAX_FOUND_TRACKS) break; struct track *track = (struct track *) ptr->val; jsonTdbSettingsBuild(jsonTdbVars, track, FALSE); // FALSE: No config from track search + char *hubId = NULL; + if (isHubTrack(track->track)) + { + char *trackNameCopy = cloneString(track->track); + hubId = strchr(trackNameCopy, '_'); + hubId += 1; + char *ptr2 = strchr(hubId, '_'); + if (ptr2 == NULL) + errAbort("hub track '%s' not in correct format", track->track); + *ptr2 = '\0'; + char *hubUrl = hashFindVal(hubIdsToUrls, hubId); + if (hubUrl != NULL) + { + struct jsonElement *ele = jsonFindNamedField(jsonTdbVars, "", track->track); + jsonObjectAdd(ele, "hubUrl", newJsonString(hubUrl)); + } + } if (tdbIsFolder(track->tdb)) // supertrack hPrintf("