ac3191c7e768e8c0c8f6c376526f029ad39f4e1b max Thu Sep 10 05:57:18 2026 -0700 hgHubConnect: on mirrors, show the Hub Upload tab as instructions, not a dialog On a site that is not the login host the tab used to render the full upload UI with a warning dialog layered over it. Show only a message instead: where to upload, a direct link to the Hub Upload tab on the US site, and how to get an uploaded hub onto this site via Connected Hubs or a hub-connecting URL. refs #38323 diff --git src/hg/js/hgMyData.js src/hg/js/hgMyData.js index 2ff488e654e..b92a55d5086 100644 --- src/hg/js/hgMyData.js +++ src/hg/js/hgMyData.js @@ -1,3078 +1,3105 @@ /* jshint esversion: 8 */ /* This file contains all the code needed to get the HubSpace UI functioning. * There are some helper functions that are sort of general and could probably * be added to utils.js or similar as well as 3 main pieces: * - the api key generation/revocation: functions to request new/revoke old apiKeys * this code runs on the Hub Development tab of hgHubConnect * - uppyOptions and uppy constructor: Uppy is a 3rd party library for handling * user uploads. The uppyOptions object and constructor are used to modify * the default behavior, including what to do when a file has been added * to the dashboard, verifying file name legality, etc. Code in these sections * also modifies the default preact/react rendering of elements, so it looks * a little different than normal kent javascript. * - BatchChangePlugin class: a custom class again used to extend the default Uppy * interface. This time to put some inputs at the bottom of the dashboard * that changes metadata for all the files a user has selected * - hubCreate: An IIFE that runs on document ready that sets up or controls the * whole UI. The UI is a combindation of Uppy for the actual file selection * and DataTables for showing the uploaded files. There are many helper functions * within this block that also could probably be moved to a lib, but haven't as * the code has evolved over time. * * TODO: most of this code could probably be modularized successfully, or split up * so it is easier to read. */ var debugCartJson = true; function prettyFileSize(num) { if (!num) {return "0B";} if (num < (1024 * 1024)) { return `${(num/1024).toFixed(1)}KB`; } else if (num < (1024 * 1024 * 1024)) { return `${((num/1024)/1024).toFixed(1)}MB`; } else { return `${(((num/1024)/1024)/1024).toFixed(1)}GB`; } } function renderTimeCell(data, type) { // DataTables renderer for the two time columns. The server sends seconds since // the epoch, so the reader sees their own timezone rather than the server's, // while ordering stays on the number if (type !== "display") { return data; } if (!data) { return ""; } return new Date(data * 1000).toLocaleString(); } function cgiEncode(value) { // copy of cheapgi.c:cgiEncode except we are explicitly leaving '/' characters, and // space becomes '+': let splitVal = value.split('/'); splitVal.forEach((ele, ix) => { if (ele == " ") { splitVal[ix] = '+'; } else { splitVal[ix] = encodeURIComponent(ele); } }); return splitVal.join('/'); } function cgiDecode(value) { // decode an encoded value return decodeURIComponent(value); } function setDbSelectFromAutocomplete(selectEle, item) { // this has been bound to the