e2002b80518d8b522ac768713cda4126cf3b5dc0
chmalee
  Thu Mar 20 12:21:10 2025 -0700
Make wording changes to hubSpace UI. Make checkbox selection not recursive, fix bug in deselect all rows checkbox, refs #31058

diff --git src/hg/js/hgMyData.js src/hg/js/hgMyData.js
index aed680bbca2..d94658e4b84 100644
--- src/hg/js/hgMyData.js
+++ src/hg/js/hgMyData.js
@@ -304,67 +304,85 @@
         let cartData = {deleteFile: {fileList: []}};
         cart.setCgi("hgHubConnect");
         _.forEach(data, (d) => {
             cartData.deleteFile.fileList.push({
                 fileName: d.fileName,
                 fileType: d.fileType,
                 parentDir: d.parentDir,
                 genome: d.genome,
                 fullPath: d.fullPath,
             });
         });
         cart.send(cartData, deleteFileSuccess);
         cart.flush();
     }
 
-    function updateSelectedFileDiv(data) {
+    function updateSelectedFileDiv(data, isFolderSelect = false) {
         // update the div that shows how many files are selected
         let numSelected = data !== null ? Object.entries(data).length : 0;
         let infoDiv = document.getElementById("selectedFileInfo");
         let span = document.getElementById("numberSelectedFiles");
         let spanParentDiv = span.parentElement;
-        span.textContent = `${numSelected} ${numSelected > 1 ? "files" : "file"}`;
         if (numSelected > 0) {
+            if (isFolderSelect || span.textContent.endsWith("hub") || span.textContent.endsWith("hubs")) {
+                span.textContent = `${numSelected} ${numSelected > 1 ? "hubs" : "hub"}`;
+            } else {
+                span.textContent = `${numSelected} ${numSelected > 1 ? "files" : "file"}`;
+            }
             // (re) set up the handlers for the selected file info div:
             let viewBtn = document.getElementById("viewSelectedFiles");
-            selectedData = data;
             viewBtn.addEventListener("click", viewAllInGenomeBrowser);
-            viewBtn.textContent = numSelected === 1 ? "View selected file in Genome Browser" : "View all selected files in Genome Browser";
+            viewBtn.textContent = "View selected";
             let deleteBtn = document.getElementById("deleteSelectedFiles");
             deleteBtn.addEventListener("click", deleteFileList);
-            deleteBtn.textContent = numSelected === 1 ? "Delete selected file" : "Delete selected files";
+            deleteBtn.textContent = "Delete selected";
+        } else {
+            span.textContent = "";
         }
 
         // set the visibility of the placeholder text and info text
         spanParentDiv.style.display = numSelected === 0 ? "none": "block";
         let placeholder = document.getElementById("placeHolderInfo");
         placeholder.style.display = numSelected === 0 ? "block" : "none";
     }
 
-    function handleCheckboxSelect(evtype, table, row) {
+    function handleCheckboxSelect(evtype, table, selectedRow) {
         // depending on the state of the checkbox, we will be adding information
-        // to the div, or removing information. We will also be potentially checking/unchecking
-        // all of the checkboxes if the selectAll box was clicked. The data variable
-        // will hold all the information we want to keep visible in the info div
-        let data = {};
+        // to the div, or removing information. We also potentially checked/unchecked
+        // all of the checkboxes if the selectAll box was clicked. If isFolderSelect
+        // is true, then in the info div, display that a hub was selected and not just
+        // a file(s)
+
+        // The data variable will hold all the information we want to keep visible in the info div
+        let data = [];
+        // The selectedData global holds the actual information needed for the view/delete buttons
+        // to work, so data plus any child rows
+        selectedData = {};
 
         // get all of the currently selected rows (may be more than just the one that
         // was most recently clicked)
         table.rows({selected: true}).data().each(function(row, ix) {
-            data[ix] = row;
+            data.push(row);
+            selectedData[row.fullPath] = row;
+            // add any newly checked rows children to the selectedData structure for the view/delete
+            if (row.children) {
+                row.children.forEach(function(child) {
+                    selectedData[child.fullPath] = child;
+                });
+            }
         });
-        updateSelectedFileDiv(data);
+        updateSelectedFileDiv(data, selectedRow.data().fileType === "dir");
     }
 
     function createOneCrumb(table, dirName, dirFullPath, doAddEvent) {
         // make a new span that can be clicked to nav through the table
         let newSpan = document.createElement("span");
         newSpan.id = dirName;
         newSpan.textContent = decodeURIComponent(dirName);
         newSpan.classList.add("breadcrumb");
         if (doAddEvent) {
             newSpan.addEventListener("click", function(e) {
                 dataTableShowDir(table, dirName, dirFullPath);
                 table.draw();
                 dataTableCustomOrder(table, {"fullPath": dirFullPath});
                 table.draw();
             });
@@ -646,43 +664,31 @@
 
         // show all the new rows we just added, note the double draw, we need
         // to have the new rows rendered to do the order because the order
         // will copy the actual DOM node
         parseFileListIntoHash(uiState.fileList);
         dataTableShowDir(table, hubDirData.fileName, hubDirData.fullPath);
         table.draw();
         dataTableCustomOrder(table, hubDirData);
         table.draw();
     }
 
     function doRowSelect(evtype, table, indexes) {
         let selectedRow = table.row(indexes);
         let rowTr = selectedRow.node();
         if (rowTr) {
-            let rowCheckbox = rowTr.childNodes[0].firstChild;
-            let rowChildren = uiState.filesHash[selectedRow.data().fullPath].children;
-            // we need to manually check the children
-            if (rowChildren) {
-                for (let child of rowChildren) {
-                    if (evtype === "select") {
-                        table.row((idx,data) => data.fullPath === child.fullPath).select();
-                    } else {
-                        table.row((idx,data) => data.fullPath === child.fullPath).deselect();
-                    }
-                }
-            }
-            handleCheckboxSelect(evtype, table, rowTr);
+            handleCheckboxSelect(evtype, table, selectedRow);
         }
     }
 
     function indentActionButton(rowTr, rowData) {
         let numIndents = "0px"; //data.parentDir !== "" ? data.fullPath.split('/').length - 1: 0;
         if (rowData.fileType !== "dir") {
             numIndents = "10px";
         }
         rowTr.childNodes[1].style.textIndent = numIndents;
     }
 
     let tableInitOptions = {
         select: {
             items: 'row',
             selector: 'td:first-child',
@@ -843,31 +849,33 @@
             document.getElementById("rootBreadcrumb").addEventListener("click", function(e) {
                 dataTableShowTopLevel(table);
                 dataTableCustomOrder(table);
                 dataTableEmptyBreadcrumb(table);
                 table.draw();
             });
         } else {
             table.buttons(".uploadButton").disable();
         }
         table.on("select", function(e, dt, type, indexes) {
             indexes.forEach(function(i) {
                 doRowSelect(e.type, dt, i);
             });
         });
         table.on("deselect", function(e, dt, type, indexes) {
-            doRowSelect(e.type, dt, indexes);
+            indexes.forEach(function(i) {
+                doRowSelect(e.type, dt, i);
+            });
         });
         table.on("click", function(e) {
             if (e.target.className !== "dt-select-checkbox") {
                 e.stopPropagation();
                 // we've clicked somewhere not on the checkbox itself, we need to:
                 // 1. open the directory if the clicked row is a directory
                 // 2. select the file if the clicked row is a regular file
                 let row = table.row(e.target);
                 let data = row.data();
                 if (data.children && data.children.length > 0) {
                     dataTableShowDir(table, data.fileName, data.fullPath);
                     dataTableCustomOrder(table, {"fullPath": data.fullPath});
                     table.draw();
                 } else {
                     if (row.selected()) {