b8b56383b460baeded0eb044c5c50998564f4b9d
jcasper
  Sun Jan 25 22:35:48 2026 -0800
Initial pass at making data types optional for the new faceted
composite UI.  refs #36320

diff --git src/hg/hgTrackUi/hgTrackUi.c src/hg/hgTrackUi/hgTrackUi.c
index ecd3c188fce..67510854f67 100644
--- src/hg/hgTrackUi/hgTrackUi.c
+++ src/hg/hgTrackUi/hgTrackUi.c
@@ -2923,89 +2923,117 @@
     "<script type='text/javascript' src='/js/facetedComposite.js'></script>\n";
 
 // parse the hgsid as id and sessionKey
 char *hgsid = cartSessionId(cart);
 char *sessionKey = NULL;
 const int id = cartDbParseId(hgsid, &sessionKey);
 if (!sessionKey)
     errAbort("Failed to parse session key from: %s", hgsid);
 
 // --- Get data from 'settings' field in 'trackDb' entry ---
 // required
 const char *metaDataUrl = trackDbSetting(tdb, "metaDataUrl");
 const char *primaryKey = trackDbSetting(tdb, "primaryKey");
 
 struct slName *dataTypes = parseDataTypes(tdb);
-if (!dataTypes)
-    errAbort("Failed to parse data types from faceted composite settings for: %s", tdb->track);
+boolean hasDataTypes = (dataTypes != NULL);
+//if (!dataTypes)
+//    errAbort("Failed to parse data types from faceted composite settings for: %s", tdb->track);
+
 // optional
 const char *colorSettingsUrl = (const char *)hashFindVal(tdb->settingsHash, "colorSettingsUrl");
 const char *maxCheckboxes = (const char *)hashFindVal(tdb->settingsHash, "maxCheckboxes");
 // --- done parsing values from trackDb.settings ---
 
 const char *metaDataId = tdb->track;
 const int metaDataIdLen = strlen(metaDataId);
 
 char queryFmt[] = "SELECT contents FROM sessionDb WHERE id='%d' AND sessionKey='%s';";
 char query[query_buff_size];
 sqlSafef(query, query_buff_size, queryFmt, id, sessionKey);
 
 struct sqlConnection *conn = hConnectCentral();
 const char *contents = sqlQuickString(conn, query);
 struct cgiParsedVars *varList = cgiParsedVarsNew((char *)contents);
 
 printf(pageStyle);       // css
 printf(placeholderDiv);  // placholder
 
 /* --- START embedded JSON data --- */
 printf(openJSON);
 printf(openDataTypesJSON);
 // find selected data types
 int not_first = 0;
 struct slName *anySelDataType = NULL;  // non-null val will be used as flag
+if (hasDataTypes)
+    {
     for (struct slName *thisType = dataTypes; thisType != NULL; thisType = thisType->next)
         {
         char toMatch[token_size];
         safef(toMatch, token_size, "_%s_sel", thisType->name);
         boolean dataTypeSel = FALSE;
         for (struct cgiVar *le = varList->list; !dataTypeSel && le; le = le->next)
             if (startsWith(metaDataId, le->name) && endsWith(le->name, toMatch))
                 dataTypeSel = TRUE;
         printf("%s\"%s\": %d", COMMA_IF(not_first), thisType->name, dataTypeSel ? 1 : 0);
         anySelDataType = dataTypeSel ? thisType : anySelDataType;
         }
+    }
+// else: dataTypes dict is empty - JS will detect this
 printf(closeDataTypesJSON);
 printf(",");  // add separator
 // find selected data sets
 printf(openDataElementsJSON);
 not_first = 0;
+if (hasDataTypes)
+    {
     if (anySelDataType != NULL)
         {
         char suffix[token_size];
         safef(suffix, token_size, "_%s_sel", anySelDataType->name);
         for (struct cgiVar *le = varList->list; le; le = le->next)
             if (startsWith(metaDataId, le->name) && endsWith(le->name, suffix))
                 {
                 const char *nameStart = le->name + metaDataIdLen + 1;
                 const char *nameEnd = strchr(nameStart, '_');
                 if (nameEnd && nameEnd > nameStart)
                     {
                     const int nameLen = nameEnd - nameStart;
                     printf("%s\"%.*s\"", COMMA_IF(not_first), nameLen, nameStart);
                     }
                 }
         }
+    }
+else
+    {
+    // No data types - look for {mdid}_{de}_sel pattern (no dataType component)
+    char suffix[] = "_sel";
+    for (struct cgiVar *le = varList->list; le; le = le->next)
+        {
+        if (startsWith(metaDataId, le->name) && endsWith(le->name, suffix))
+            {
+            // Extract data element name: between mdid_ and _sel
+            const char *nameStart = le->name + metaDataIdLen + 1;
+            const char *nameEnd = strstr(nameStart, "_sel");
+            if (nameEnd && nameEnd > nameStart)
+                {
+                const int nameLen = nameEnd - nameStart;
+                printf("%s\"%.*s\"", COMMA_IF(not_first), nameLen, nameStart);
+                }
+            }
+        }
+    }
 printf(closeDataElementsJSON);
 printf(",\"mdid\": \"%s\"", metaDataId);
 printf(",\"primaryKey\": \"%s\"", primaryKey);  // must exist
 if (maxCheckboxes) // only if present in trackDb.settings entry
     printf(",\"maxCheckboxes\": \"%s\"", maxCheckboxes);
 if (colorSettingsUrl) // only if present in trackDb.settings entry
     printf(",\"colorSettingsUrl\": \"%s\"", colorSettingsUrl);
 printf(",\"metadataUrl\": \"%s\"", metaDataUrl);
 printf(closeJSON);
 /* --- END embedded JSON data --- */
 
 printf(metadataTableScriptElement);
 
 // cleanup
 slFreeList(&dataTypes);