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
@@ -3024,43 +3024,70 @@
             return true;
         }
         return false;
     }
 
     function handleRefreshState(jsonData, textStatus) {
         if (checkJsonData(jsonData, 'handleRefreshState')) {
             handleGetFileList(jsonData, true);
         }
     }
 
     function handleErrorState(jqXHR, textStatus) {
         cart.defaultErrorCallback(jqXHR, textStatus);
     }
 
+    function showMirrorOnlyMessage() {
+        // On the mirrors there is no upload infrastructure, so instead of layering a
+        // dialog over a tab that cannot be used, replace the tab with instructions on
+        // where to upload and how to get the uploaded hub back onto this site.
+        let uploadUrl = `${loginHost}/cgi-bin/hgHubConnect#hubUpload`;
+        let hostName = loginHost.replace(/^https?:\/\//, "");
+        $("#hubUpload").html(
+            `<div class='tabSection'>` +
+            `<h4>Hub upload is only possible on ${hostName}</h4>` +
+            `<p>Files can only be uploaded on our main US-based site, for speed reasons. ` +
+            `Your uploaded files are stored there and are not copied to this mirror.</p>` +
+            `<p><a href="${uploadUrl}" style="color:#121E9A"><b>Go to Hub Upload on ${hostName}</b></a></p>` +
+            `<p>A hub that you upload there can be used on any of our sites, including this one. ` +
+            `To use one of your uploaded hubs here:</p>` +
+            `<ol>` +
+            `<li>Upload your files on <a href="${uploadUrl}" style="color:#121E9A">${hostName}</a>.</li>` +
+            `<li>In the file table there, right-click the hub.txt file of your hub and select ` +
+            `"Copy link" to get its URL.</li>` +
+            `<li>Paste this URL into the ` +
+            `<a href="hgHubConnect#unlistedHubs" style="color:#121E9A">Connected Hubs</a> tab ` +
+            `on this site. You can also build a link that connects the hub automatically, see ` +
+            `<a href="../goldenPath/help/hgTrackHubHelp.html#Sharing" ` +
+            `style="color:#121E9A" target="_blank">Sharing Track Hubs</a>.</li>` +
+            `</ol>` +
+            `</div>`);
+    }
+
     let inited = false; // keep track of first init for tab switching purposes
     function init() {
         cart.setCgiAndUrl(fileListEndpoint);
         cart.debug(debugCartJson);
         // get the file list immediately upon page load
         let activeTab = $("#tabs").tabs( "option", "active" );
         if (activeTab === 3) {
             let url = new URL(window.location.href);
             if (url.protocol === "http:") {
                 warn(`The hub upload feature is only available over HTTPS. Please load the HTTPS version of ` +
                         `our site: <a href="https:${url.host}${url.pathname}${url.search}">https:${url.host}${url.pathname}${url.search}</a>`);
             } else if ((url.protocol + "//" + url.host) !== loginHost) {
-                warn(`The hub upload feature is only avaiable on our US based public site (<a href="${loginHost}">${loginHost}</a>) for speed purposes. Please go there to upload your hubs, copy the links to the hub.txt files, then use the Connected Hubs tab here to view your files.`);
+                showMirrorOnlyMessage();
             } else if (!inited && isLoggedIn) {
                 cart.send({ getHubSpaceUIState: {}}, handleRefreshState, handleErrorState);
                 cart.flush();
             } else {
                 showExistingFiles([]);
             }
         }
     }
 
     return { init: init,
              uiState: uiState,
              defaultDb: defaultDb,
              makeGenomeSelectOptions: makeGenomeSelectOptions,
              getDefaultHubName: getDefaultHubName,
              detectFileType: detectFileType,