7864ddf3a6d058dbe29f706519921cd55ccc4c67
chmalee
  Thu May 2 09:04:45 2024 -0700
Work in progress on building form for choosing db and hub along with files to submit

diff --git src/hg/js/hgMyData.js src/hg/js/hgMyData.js
index 2859570..dff2ea5 100644
--- src/hg/js/hgMyData.js
+++ src/hg/js/hgMyData.js
@@ -52,32 +52,30 @@
         let li = document.getElementById(liId);
         return li;
     }
 
     function newButton(text) {
         /* Creates a new button with some text as the label */
         let newBtn = document.createElement("label");
         newBtn.classList.add("button");
         newBtn.textContent = text;
         return newBtn;
     }
 
     function createInput() {
         /* Create a new input element for a file picker */
         let input = document.createElement("input");
-        //input.style.opacity = 0;
-        //input.style.float = "right";
         input.multiple = true;
         input.type = "file";
         input.id = "hiddenFileInput";
         input.style = "display: none";
         input.addEventListener("change", listPickedFiles);
         return input;
     }
 
     function requestsPending() {
         /* Return true if requests are still pending, which means it needs to
          * have been sent(). aborted requests are considered done for this purpose */
         for (let [req, f] of uiState.pendingQueue) {
             if (req._req !== null) {
                 xreq = req._req._xhr;
                 if (xreq.readyState != XMLHttpRequest.DONE && xreq.readyState != XMLHttpRequest.UNSENT) {
@@ -150,30 +148,31 @@
         ele.appendChild(progMeter);
         progMeter.ctx = progMeter.getContext('2d');
         progMeter.ctx.fillStyle = 'orange';
         progMeter.updateProgress = (percent) => {
             // update the progress meter for this elem
             if (percent === 100) {
                 progMeter.ctx.fillStyle = 'green';
             }
             progMeter.ctx.fillRect(0, 0, (progMeterWidth * percent) / 100, progMeterHeight);
         };
         progMeter.updateProgress(0);
         return progMeter;
     }
 
     function submitPickedFiles() {
+        
         let tusdServer = getTusdEndpoint();
 
         let onBeforeRequest = function(req) {
             let xhr = req.getUnderlyingObject(req);
             xhr.withCredentials = true;
         };
 
         let onSuccess = function(req) {
             // remove the selected file from the input element and the ul list
             // FileList is a read only setting, so we have to make
             // a new one without this req
             delete uiState.toUpload[req.name];
             let i, newReqObj = {};
             for (i = 0; i < uiState.pendingQueue.length; i++) {
                 fname = uiState.pendingQueue[i][1].name;
@@ -263,53 +262,102 @@
             submitBtn.id = "submitPicked";
             submitBtn.classList.add("button");
             submitBtn.textContent = "Submit";
             submitBtn.addEventListener("click", submitPickedFiles);
             btnRow.append(submitBtn);
         }
     }
 
     function removeClearSubmitButtons() {
         let btn = document.getElementById("clearPicked");
         btn.parentNode.removeChild(btn);
         btn = document.getElementById("submitPicked");
         btn.parentNode.removeChild(btn);
     }
 
+    function makeGenomeSelect(formName, fileName) {
+        let genomeInp = document.createElement("select");
+        genomeInp.classList.add("genomePicker");
+        genomeInp.name = `${fileName}#genomeInput`;
+        genomeInp.id = `${fileName}#genomeInput`;
+        genomeInp.form = formName;
+        return genomeInp;
+    }
+
+    function makeTypeSelect(formName, fileName) {
+        let typeInp = document.createElement("select");
+        typeInp.classList.add("typePicker");
+        typeInp.name = `${fileName}#typeInput`;
+        typeInp.id = `${fileName}#typeInput`;
+        let choices = ["hub.txt", "bigBed", "bam", "vcf", "bigWig"];
+        choices.forEach( (e) =>  {
+            let choice = document.createElement("option");
+            choice.id = e;
+            choice.label = e;
+            choice.value = e;
+            typeInp.appendChild(choice);
+        });
+        typeInp.form = formName;
+        return typeInp;
+    }
+
+    function makeHubSelect(formName, fileName) {
+        let hubInp = document.createElement("select");
+        hubInp.classList.add("hubPicker");
+        hubInp.name = `${fileName}#hubInput`;
+        hubInp.id = `${fileName}#hubInput`;
+        hubInp.form = formName;
+    }
+
+    function makeFormControlsForFile(li, formName, fileName) {
+        typeInp = makeTypeSelect(formName, fileName);
+        genomeInp = makeGenomeSelect(formName, fileName);
+        hubInp = makeGenomeSelect(formName, fileName);
+        li.append(typeInp);
+        li.append(genomeInp);
+        li.append(hubInp);
+    }
+
     function listPickedFiles() {
-        //uiState.input.click(); // let the user choose files:
+        // let the user choose files:
         if (uiState.input.files.length === 0) {
             console.log("not input");
             return;
-            //togglePickStateMessage(true);
-            //removeClearSubmitButtons();
         } else {
-            let displayList = document.getElementsByClassName("pickedFiles");
-            if (displayList.length === 0) {
+            let displayList;
+            let displayListForm = document.getElementsByClassName("pickedFilesForm");
+            if (displayListForm.length === 0) {
+                displayListForm = document.createElement("form");
+                displayListForm.id = "displayListForm";
+                displayListForm.classList.add("pickedFilesForm");
                 displayList = document.createElement("ul");
                 displayList.classList.add("pickedFiles");
-                uiState.pickedList.appendChild(displayList);
+                displayListForm.appendChild(displayList);
+                uiState.pickedList.appendChild(displayListForm);
             } else {
-                displayList = displayList[0];
+                displayList = displayListForm[0].firstChild;
             } 
             for (let file of uiState.input.files ) {
                 if (file.name in uiState.toUpload) { continue; }
                 // create a list for the user to see
                 let li = document.createElement("li");
                 li.classList.add("pickedFile");
                 li.id = `${file.name}#li`;
                 li.textContent = `File name: ${file.name}, file size: ${prettyFileSize(file.size)}`;
+                // Add the form controls for this file:
+                makeFormControlsForFile(li, "displayListForm", file.name);
+                
                 displayList.appendChild(li);
 
                 // finally add it for us
                 uiState.toUpload[file.name] = file;
             }
             togglePickStateMessage(false);
             addClearSubmitButtons();
         }
         // always clear the input element
         uiState.input = createInput();
     }
 
     function dataTablePrintSize(data, type, row, meta) {
         return prettyFileSize(data);
     }
@@ -328,31 +376,31 @@
         // Note that repeated requests, like from a bot, will return 404 as a correct response
         console.log(`sending delete req for ${fname}`);
         const endpoint = "../cgi-bin/hgHubConnect?deleteFile=" + fname;
         if (!(endpoint in pendingDeletes)) {
             const xhr = new XMLHttpRequest();
             pendingDeletes[endpoint] = xhr;
             this.xhr = xhr;
             this.xhr.open("DELETE", endpoint, true);
             this.xhr.send();
             deleteFileFromTable(rowIx, fname);
             delete pendingDeletes[endpoint];
         }
     }
 
     function viewInGenomeBrowser(rowIx, fname) {
-        // redirect to hgTracks with this track as a custom track
+        // redirect to hgTracks with this track open in the hub
         if (typeof uiState.userUrl !== "undefined" && uiState.userUrl.length > 0) {
             bigBedExts = [".bb", ".bigBed", ".vcf.gz", ".vcf", ".bam", ".bw", ".bigWig"];
             let i;
             for (i = 0; i < bigBedExts.length; i++) {
                 if (fname.toLowerCase().endsWith(bigBedExts[i].toLowerCase())) {
                     // TODO: tusd should return this location in it's response after
                     // uploading a file and then we can look it up somehow, the cgi can
                     // write the links directly into the html directly for prev uploaded files maybe?
                     window.location.assign("../cgi-bin/hgTracks?db=hg38&hgt.customText=" + uiState.userUrl + fname);
                     return false;
                 }
             }
         }
     }
 
@@ -370,111 +418,103 @@
 
     let tableInitOptions = {
         //columnDefs: [{orderable: false, targets: [0,1]}],
         columnDefs: [
             {
                 orderable: false, targets: 0,
                 title: "<input type=\"checkbox\"></input>",
                 render: function(data, type, row) {
                     return "<input type=\"checkbox\"></input>";
                 }
             },
             {
                 orderable: false, targets: 1,
                 data: "action", title: "Action",
                 render: function(data, type, row) {
-                    // TODO: add event handler on delete button
                     // click to call hgHubDelete file
                     return "<button class='deleteFileBtn'>Delete</button><button class='viewInBtn'>View In GB</button>";
                 }
             },
             {
                 targets: 3,
                 render: function(data, type, row) {
                     return dataTablePrintSize(data);
                 }
             }
         ],
         columns: [
             {data: "", },
             {data: "", },
+            {data: "hub", title: "Hub"},
+            {data: "genome", title: "Genome"},
             {data: "name", title: "File name"},
             {data: "size", title: "File size", render: dataTablePrintSize},
             {data: "createTime", title: "Creation Time"},
         ],
-        order: [[4, 'desc']],
+        order: [[6, 'desc']],
         drawCallback: function(settings) {
             let btns = document.querySelectorAll('.deleteFileBtn');
             let i;
             for (i = 0; i < btns.length; i++) {
                 let fnameNode = btns[i].parentNode.nextElementSibling.childNodes[0];
                 if (fnameNode.nodeName !== "#text") {continue;}
                 let fname = fnameNode.nodeValue;
                 btns[i].addEventListener("click", (e) => {
                     deleteFile(i, fname);
                 });
             }
             btns = document.querySelectorAll('.viewInBtn');
             for (i = 0; i < btns.length; i++) {
                 let fnameNode = btns[i].parentNode.nextElementSibling.childNodes[0];
                 if (fnameNode.nodeName !== "#text") {continue;}
                 let fname = fnameNode.nodeValue;
                 btns[i].addEventListener("click", (e) => {
                     viewInGenomeBrowser(i, fname);
                 });
             }
         },
     };
 
     function showExistingFiles(d) {
         // Make the DataTable for each file
-        //$(document).on("draw.dt", function() {alert("table redrawn");});
         tableInitOptions.data = d;
         let table = $("#filesTable").DataTable(tableInitOptions);
     }
 
     function checkJsonData(jsonData, callerName) {
         // Return true if jsonData isn't empty and doesn't contain an error;
         // otherwise complain on behalf of caller.
         if (! jsonData) {
             alert(callerName + ': empty response from server');
         } else if (jsonData.error) {
             console.error(jsonData.error);
             alert(callerName + ': error from server: ' + jsonData.error);
         } else if (jsonData.warning) {
             alert("Warning: " + jsonData.warning);
             return true;
         } else {
             if (debugCartJson) {
                 console.log('from server:\n', jsonData);
             }
             return true;
         }
         return false;
     }
 
     function updateStateAndPage(jsonData, doSaveHistory) {
         // Update uiState with new values and update the page.
         _.assign(uiState, jsonData);
-        /*
-        urlVars = {"db": db, "search": uiState.search, "showSearchResults": ""};
-        // changing the url allows the history to be associated to a specific url
-        var urlParts = changeUrl(urlVars);
-        if (doSaveHistory)
-            saveHistory(uiState, urlParts);
-        changeSearchResultsLabel();
-        */
     }
 
     function handleRefreshState(jsonData) {
         if (checkJsonData(jsonData, 'handleRefreshState')) {
             updateStateAndPage(jsonData, true);
         }
         $("#spinner").remove();
     }
 
     function init() {
         cart.setCgi('hgMyData');
         cart.debug(debugCartJson);
         if (!useTus) {
             console.log("tus is not supported, falling back to XMLHttpRequest");
         }