af86e1b9d932d0834eee1be7fe2ca77166203c48
angie
  Wed Mar 3 18:37:10 2021 -0800
Add row of quick download links between button row and summary table.

diff --git src/hg/hgPhyloPlace/phyloPlace.c src/hg/hgPhyloPlace/phyloPlace.c
index 184faff..cf2966e 100644
--- src/hg/hgPhyloPlace/phyloPlace.c
+++ src/hg/hgPhyloPlace/phyloPlace.c
@@ -2002,30 +2002,40 @@
     struct lm *lm = lmInit(0);
     struct bigBedInterval *bb, *bbList = bigBedIntervalQuery(bbi, chrom, 0, chromSize, 0, lm);
     for (bb = bbList;  bb != NULL;  bb = bb->next)
         {
         char *extra = bb->rest;
         char *reason = nextWord(&extra);
         int i;
         for (i = bb->start;  i < bb->end;  i++)
             slNameAddHead(&pSites[i], reason);
         }
     bigBedFileClose(&bbi);
     }
 return pSites;
 }
 
+static void downloadsRow(char *treeFile, char *sampleSummaryFile, char *spikeSummaryFile)
+/* Make a row of quick download file links, to appear between the button row & big summary table. */
+{
+printf("<p><b>Downloads:</b> | ");
+printf("<a href='%s' download>Global phylogenetic tree with your sequences</a> | ", treeFile);
+printf("<a href='%s' download>TSV summary of sequences and placements</a> | ", sampleSummaryFile);
+printf("<a href='%s' download>TSV summary of Spike mutations</a> |", spikeSummaryFile);
+puts("</p>");
+}
+
 static int subTreeInfoUserSampleCmp(const void *pa, const void *pb)
 /* Compare subtreeInfo by number of user sample IDs (highest number first). */
 {
 struct subtreeInfo *tiA = *(struct subtreeInfo **)pa;
 struct subtreeInfo *tiB = *(struct subtreeInfo **)pb;
 return slCount(tiB->subtreeUserSampleIds) - slCount(tiA->subtreeUserSampleIds);
 }
 
 char *phyloPlaceSamples(struct lineFile *lf, char *db, char *defaultProtobuf,
                         boolean doMeasureTiming, int subtreeSize, int fontHeight)
 /* Given a lineFile that contains either FASTA or VCF, prepare VCF for usher;
  * if that goes well then run usher, report results, make custom track files
  * and return the top-level custom track file; otherwise return NULL. */
 {
 char *ctFile = NULL;
@@ -2150,71 +2160,73 @@
             {
             AllocVar(jsonTns[ix]);
             trashDirFile(jsonTns[ix], "ct", "subtreeAuspice", ".json");
             treeToAuspiceJson(ti, db, geneInfoList, gSeqWin, sampleMetadata, jsonTns[ix]->forCgi,
                               source);
             }
         puts("<p></p>");
         int subtreeButtonCount = subtreeCount;
         if (seqCount > MAX_SEQ_DETAILS || subtreeCount > MAX_SUBTREE_BUTTONS)
             subtreeButtonCount = 0;
         makeButtonRow(singleSubtreeJsonTn, jsonTns, subtreeButtonCount, isFasta);
         printf("<p>If you have metadata you wish to display, click a 'view subtree in "
                "Nextstrain' button, and then you can drag on a CSV file to "
                "<a href='"NEXTSTRAIN_DRAG_DROP_DOC"' target=_blank>add it to the tree view</a>."
                "</p>\n");
+
+        // Make custom tracks for uploaded samples and subtree(s).
+        struct phyloTree *sampleTree = NULL;
+        struct tempName *ctTn = writeCustomTracks(vcfTn, results, sampleIds, bigTree->tree,
+                                                  source, fontHeight, &sampleTree, &startTime);
+
+        // Make a sample summary TSV file and accumulate S gene changes
+        struct hash *spikeChanges = hashNew(0);
+        struct tempName *tsvTn = writeTsvSummary(results, sampleTree, sampleIds, seqInfoList,
+                                                 geneInfoList, gSeqWin, spikeChanges, &startTime);
+        struct tempName *sTsvTn = writeSpikeChangeSummary(spikeChanges, slCount(sampleIds));
+        downloadsRow(results->bigTreePlusTn->forHtml, tsvTn->forHtml, sTsvTn->forHtml);
+
         if (seqCount <= MAX_SEQ_DETAILS)
             {
             summarizeSequences(seqInfoList, isFasta, results, jsonTns, sampleMetadata, bigTree,
                                refGenome);
             reportTiming(&startTime, "write summary table (including reading in lineages)");
             for (ix = 0, ti = results->subtreeInfoList;  ti != NULL;  ti = ti->next, ix++)
                 {
                 int subtreeUserSampleCount = slCount(ti->subtreeUserSampleIds);
                 printf("<h3>Subtree %d: ", ix+1);
                 if (subtreeUserSampleCount > 1)
                     printf("%d related samples", subtreeUserSampleCount);
                 else if (subtreeCount > 1)
                     printf("Unrelated sample");
                 printf("</h3>\n");
                 makeNextstrainButtonN("viewNextstrainSub", ix, jsonTns);
                 puts("<br>");
                 // Make a sub-subtree with only user samples for display:
                 struct phyloTree *subtree = phyloOpenTree(ti->subtreeTn->forCgi);
                 subtree = phyloPruneToIds(subtree, ti->subtreeUserSampleIds);
                 describeSamplePlacements(ti->subtreeUserSampleIds, results->samplePlacements,
                                          subtree, sampleMetadata, bigTree, source);
                 }
             reportTiming(&startTime, "describe placements");
             }
         else
             printf("<p>(Skipping details and subtrees; "
                    "you uploaded %d sequences, and details/subtrees are shown only when "
                    "you upload at most %d sequences.)</p>\n",
                    seqCount, MAX_SEQ_DETAILS);
 
-        // Make custom tracks for uploaded samples and subtree(s).
-        struct phyloTree *sampleTree = NULL;
-        struct tempName *ctTn = writeCustomTracks(vcfTn, results, sampleIds, bigTree->tree,
-                                                  source, fontHeight, &sampleTree, &startTime);
-
-        // Make a sample summary TSV file and accumulate S gene changes
-        struct hash *spikeChanges = hashNew(0);
-        struct tempName *tsvTn = writeTsvSummary(results, sampleTree, sampleIds, seqInfoList,
-                                                 geneInfoList, gSeqWin, spikeChanges, &startTime);
-        struct tempName *sTsvTn = writeSpikeChangeSummary(spikeChanges, slCount(sampleIds));
-
         // Offer big tree w/new samples for download
         puts("<h3>Downloads</h3>");
         puts("<ul>");
         printf("<li><a href='%s' download>SARS-CoV-2 phylogenetic tree "
                "with your samples (Newick file)</a>\n", results->bigTreePlusTn->forHtml);
         printf("<li><a href='%s' download>TSV summary of sequences and placements</a>\n",
                tsvTn->forHtml);
         printf("<li><a href='%s' download>TSV summary of S (Spike) gene changes</a>\n",
                sTsvTn->forHtml);
         for (ix = 0, ti = results->subtreeInfoList;  ti != NULL;  ti = ti->next, ix++)
            {
             int subtreeUserSampleCount = slCount(ti->subtreeUserSampleIds);
             printf("<li><a href='%s' download>Subtree with %s", ti->subtreeTn->forHtml,
                    ti->subtreeUserSampleIds->name);
             if (subtreeUserSampleCount > 10)
@@ -2231,27 +2243,27 @@
             if (subtreeUserSampleCount > 10)
                 printf(" and %d other samples", subtreeUserSampleCount - 1);
             else
                 {
                 struct slName *sln;
                 for (sln = ti->subtreeUserSampleIds->next;  sln != NULL;  sln = sln->next)
                     printf(", %s", sln->name);
                 }
             puts(" (JSON file)</a>");
             }
         puts("</ul>");
 
         // Notify in opposite order of custom track creation.
         puts("<h3>Custom tracks for viewing in the Genome Browser</h3>");
         printf("<p>Added custom track of uploaded samples.</p>\n");
-        if (subtreeCount <= MAX_SUBTREE_CTS)
+        if (subtreeCount > 0 && subtreeCount <= MAX_SUBTREE_CTS)
             printf("<p>Added %d subtree custom track%s.</p>\n",
                    subtreeCount, (subtreeCount > 1 ? "s" : ""));
         ctFile = urlFromTn(ctTn);
         }
     else
         {
         warn("No subtree output from usher.\n");
         }
     }
 return ctFile;
 }