6cbe668f98ab263238542b8fd6bbf860db113930 angie Wed Jan 28 09:55:13 2015 -0800 Several major changes in the way data sources are represented: 1. Instead of the CGI sending menus for group, track and table, make it send the whole tree of groups, tracks, views, subtracks -- "groupedTrackDb". Now the client-side model can make menus that reflect the tree structure. This also gives us flexibility to tweak labels easily. 2. Instead of hardcoding group, track and table into elements of hgai_querySpec.dataSources, make each data source a proper object with a trackPath (path through groupedTrackDb), and for the UI, other attributes like label and URL for hgTables schema page. When the CGI unpacks hgai_querySpec.dataSources, it now uses trackPath and gets table from the leaf track or subtrack (the last item in trackPath). Note: this doesn't work for old Conservation tracks that don't have views/subtracks -- need to figure out how to fudge subtracks for those. 3. Limit the number of data sources to 5, don't let the user add the same data source twice, and remember which track the user most recently selected in the "Add Data Source" section. Also, in hgAi.jsx, I separated out a bunch of things that were rendered in the top-level AppComponent into subcomponents to add some granularity to "Loading..." sections (instead of making the whole page saying "Loading..." until everything is in place). diff --git src/hg/hgAi/hgAi.c src/hg/hgAi/hgAi.c index aed3461..5b0bfd1 100644 --- src/hg/hgAi/hgAi.c +++ src/hg/hgAi/hgAi.c @@ -26,31 +26,33 @@ #include "annoFormatTab.h" #include "annoGratorQuery.h" /* Global Variables */ struct cart *cart = NULL; /* CGI and other variables */ #define QUERY_SPEC "hgai_querySpec" #define DO_QUERY "hgai_doQuery" //#*** duplicated from hgVai... put in some anno*.h? #define NO_MAXROWS 0 static void writeDbMetadata(struct cartJson *cj, struct hash *paramHash) /* Send all the info that we'll need for working with a specific assembly db. */ { -cartJsonGetGroupsTracksTables(cj, paramHash); +struct hash *gtdbParamHash = hashNew(0); +hashAdd(gtdbParamHash, "fields", newJsonString("track,table,shortLabel,parent,subtracks")); +cartJsonGetGroupedTrackDb(cj, gtdbParamHash); //#*** TODO: move jsonStringEscape inside jsonWriteString char *encoded = jsonStringEscape(cartOptionalString(cart, QUERY_SPEC)); jsonWriteString(cj->jw, QUERY_SPEC, encoded); } static void changeDb(struct cartJson *cj, struct hash *paramHash) /* The user has changed db; send groups, tracks, tables etc. for the new db. */ { cartJsonChangeDb(cj, paramHash); writeDbMetadata(cj, paramHash); } static void changeOrg(struct cartJson *cj, struct hash *paramHash) /* The user has changed org/genome; send groups, tracks, tables etc. for the new default db. */ { @@ -216,37 +218,45 @@ struct pipeline *textOutPipe = configTextOut(queryObj, &savedStdout); webStartText(); // Build annoGrator query. struct slRef *dataSources = jsonListVal(jsonFindNamedField(queryObj, "queryObj", "dataSources"), "dataSources"); struct grp *fullGroupList = NULL; struct trackDb *fullTrackList = NULL; cartTrackDbInit(cart, &fullTrackList, &fullGroupList, TRUE); struct annoStreamer *primary = NULL; struct annoGrator *gratorList = NULL; struct slRef *dsRef; int i; for (i = 0, dsRef = dataSources; dsRef != NULL; i++, dsRef = dsRef->next) { struct jsonElement *dsObj = dsRef->val; - char *table = jsonStringField(dsObj, "table"); - char *track = jsonStringField(dsObj, "track"); - struct trackDb *tdb = tdbForTrack(db, table, &fullTrackList); + struct slRef *trackPath = jsonListVal(jsonMustFindNamedField(dsObj, "dataSource", "trackPath"), + "trackPath"); + // The first item in trackPath is group. The second is track (or composite): + struct jsonElement *trackEl = (struct jsonElement *)(trackPath->next->val); + // and the last item in trackPath is track or leaf subtrack. + struct slRef *leafRef = slLastEl(trackPath); + struct jsonElement *leafEl = (struct jsonElement *)(leafRef->val); + char *leafTrack = jsonStringVal(leafEl, "leaf"); + char *track = jsonStringVal(trackEl, "track"); + struct trackDb *tdb = tdbForTrack(db, leafTrack, &fullTrackList); if (!tdb) tdb = tdbForTrack(db, track, &fullTrackList); if (!tdb) - errAbort("doQuery: no tdb for track %s, table %s", track, table); + errAbort("doQuery: no tdb for track %s, leaf %s", track, leafTrack); + char *table = tdb->table; if (i == 0) { primary = hAnnoStreamerFromTrackDb(assembly, table, tdb, chrom, NO_MAXROWS); annoStreamerSetName(primary, table); } else { struct annoGrator *grator = hAnnoGratorFromTrackDb(assembly, table, tdb, chrom, NO_MAXROWS, NULL, agoNoConstraint); if (grator) { annoStreamerSetName((struct annoStreamer *)grator, table); slAddHead(&gratorList, grator); } else