a4c8987ac13d72f85a7c3adde3f867456a85516f chmalee Thu Sep 26 15:52:46 2024 -0700 Save newly created hubs to file table, return hubs when loading the page diff --git src/hg/js/hgMyData.js src/hg/js/hgMyData.js index e015aeb..1aa42f2 100644 --- src/hg/js/hgMyData.js +++ src/hg/js/hgMyData.js @@ -1,36 +1,39 @@ /* jshint esnext: true */ debugCartJson = true; function prettyFileSize(num) { + if (!num) {return "n/a";} if (num < (1000 * 1024)) { return `${(num/1000).toFixed(1)}kb`; } else if (num < (1000 * 1000 * 1024)) { return `${((num/1000)/1000).toFixed(1)}mb`; } else { return `${(((num/1000)/1000)/1000).toFixed(1)}gb`; } } var hubCreate = (function() { let uiState = { // our object for keeping track of the current UI and what to do toUpload: {}, // set of file objects keyed by name input: null, // the hidden input element pickedList: null, // the <div> for displaying files in toUpload pendingQueue: [], // our queue of pending [tus.Upload, file], kind of like the toUpload object fileList: [], // the files this user has uploaded, initially populated by the server // on page load, but gets updated as the user uploades/deletes files + hubList: [], // the hubs this user has created/uploaded, initially populated by server + // on page load, but gets updated as the user creates/deletes hubs userUrl: "", // the web accesible path where the uploads are stored for this user }; // We can use XMLHttpRequest if necessary or a mirror can't use tus var useTus = tus.isSupported && true; function getTusdEndpoint() { // return the port and basepath of the tusd server // NOTE: the port and basepath are specified in hg.conf //let currUrl = parseUrl(window.location.href); return "https://hgwdev-hubspace.gi.ucsc.edu/files"; } function togglePickStateMessage(showMsg = false) { if (showMsg) { @@ -424,30 +427,38 @@ function addNewUploadedFileToTable(req) { // req is an object with properties of an uploaded file, make a new row // for it in the filesTable let table = null; if ($.fn.dataTable.isDataTable("#filesTable")) { table = $("#filesTable").DataTable(); let newRow = table.row.add(req).draw(); } else { showExistingFiles([req]); } } function createHubSuccess(jqXhr, textStatus) { console.log(jqXhr); $("#newTrackHubDialog").dialog("close"); + addNewUploadedFileToTable({ + createTime: jqXhr.creationTime, + fileType: "hub", + fileName: jqXhr.hubName, + genome: jqXhr.db, + fileSize: null, + hub: jqXhr.hubName + }); } function createHub(db, hubName) { // send a request to hgHubConnect to create a hub for this user cart.setCgi("hgHubConnect"); cart.send({createHub: {db: db, name: hubName}}, createHubSuccess, null); cart.flush(); } function startHubCreate() { // put up a dialog to walk a user through setting up a track hub console.log("create a hub button clicked!"); $("#newTrackHubDialog").dialog({ minWidth: $("#newTrackHubDialog").width(), }); @@ -471,85 +482,146 @@ ] } }, 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) { + /* Return a node for rendering the actions column */ + // all of our actions will be buttons in this div: + let container = document.createElement("div"); + // click to call hgHubDelete file - return "<button class='deleteFileBtn'>Delete</button><button class='viewInBtn'>View In GB</button>"; + let delBtn = document.createElement("button"); + delBtn.textContent = "Delete"; + delBtn.type = 'button'; + delBtn.addEventListener("click", function() { + deleteFile(0, row.fileName); + }); + + // click to view hub/file in gb: + let viewBtn = document.createElement("button"); + viewBtn.textContent = "View in Genome Browser"; + viewBtn.type = 'button'; + viewBtn.addEventListener("click", function() { + viewInGenomeBrowser(row.fileName, row.genome); + }); + + // click to rename file or hub: + let renameBtn = document.createElement("button"); + renameBtn.textContent = "Rename"; + renameBtn.type = 'button'; + renameBtn.addEventListener("click", function() { + console.log("rename btn clicked!"); + }); + + // click to associate this track to a hub + let addToHubBtn = document.createElement("button"); + addToHubBtn.textContent = "Add to hub"; + addToHubBtn.type = 'button'; + addToHubBtn.addEventListener("click", function() { + console.log("add to hub button clicked!"); + }); + + container.appendChild(delBtn); + container.appendChild(viewBtn); + container.appendChild(renameBtn); + container.appendChild(addToHubBtn); + + return container; } }, { targets: 3, render: function(data, type, row) { return dataTablePrintSize(data); } } ], columns: [ {data: "", }, {data: "", }, {data: "fileName", title: "File name"}, {data: "fileSize", title: "File size", render: dataTablePrintSize}, {data: "fileType", title: "File type"}, {data: "genome", title: "Genome"}, {data: "hub", title: "Hubs"}, {data: "createTime", title: "Creation Time"}, ], order: [[6, 'desc']], + /* drawCallback: function(settings) { + // every time we draw we need to update event handlers if we've added/deleted a row let table = this.DataTable(); btns = document.querySelectorAll('.deleteFileBtn'); let i, numRows= table.rows().data().length; for (i = 0; i < numRows; i++) { let fname = table.cell(i, 2).data(); btns[i].addEventListener("click", (e) => { deleteFile(i, fname); }); } btns = document.querySelectorAll('.viewInBtn'); for (i = 0; i < numRows; i++) { let fname = table.cell(i, 2).data(); let genome = table.cell(i, 5).data(); btns[i].addEventListener("click", (e) => { viewInGenomeBrowser(fname, genome); }); } }, + */ }; function showExistingFiles(d) { // Make the DataTable for each file // make buttons have the same style as other buttons $.fn.dataTable.Buttons.defaults.dom.button.className = 'button'; tableInitOptions.data = d; let table = new DataTable("#filesTable", tableInitOptions); let toRemove = document.getElementById("welcomeDiv"); if (d.length > 0 && toRemove !== null) { toRemove.remove(); } } + function showExistingHubs(d) { + // Add the hubs to the files table + let table = $("#filesTable").DataTable(); + d.forEach((hub) => { + let hubName = hub.hubName; + let db = hub.genome; + let data = { + fileName: hubName, + fileSize: null, + fileType: "hub", + genome: db, + hub: hubName, + createTime: null, + }; + table.row.add(data).draw(); + }); + } + 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); } @@ -608,36 +680,37 @@ } else { // no cartJson object means we are coming to the page for the first time: //cart.send({ getUiState: {} }, handleRefreshState); //cart.flush(); // TODO: initialize buttons, check if there are already files // TODO: write functions for // after picking files // choosing file types // creating default trackDbs // editing trackDbs let welcomeDiv = document.createElement("div"); welcomeDiv.id = "welcomeDiv"; welcomeDiv.textContent = "Once files are uploaded they will display here. Click \"Choose files\" above or \"Create Hub\" below to get started"; let fileDiv = document.getElementById('filesDiv'); fileDiv.insertBefore(welcomeDiv, fileDiv.firstChild); - if (typeof userFiles !== 'undefined' && typeof userFiles.fileList !== 'undefined' && - userFiles.fileList.length > 0) { + if (typeof userFiles !== 'undefined' && (userFiles.fileList.length > 0 || userFiles.hubList.length > 0)) { uiState.fileList = userFiles.fileList; + uiState.hubList = userFiles.hubList; uiState.userUrl = userFiles.userUrl; } showExistingFiles(uiState.fileList); + showExistingHubs(uiState.hubList); inputBtn.addEventListener("click", (e) => uiState.input.click()); //uiState.input.addEventListener("change", listPickedFiles); // TODO: add event handler for when file is succesful upload // TODO: add event handlers for editing defaults, grouping into hub // TODO: display quota somewhere // TODO: customize the li to remove the picked file } $("#newTrackHubDialog").dialog({ modal: true, autoOpen: false, title: "Create new track hub", closeOnEscape: true, minWidth: 400, minHeight: 120 });