3f97b357c5967755f1e5c914663ce9c7cc385e70
max
  Wed Aug 26 03:01:34 2026 -0700
Share a link: create the session only when the user asks, and copy in one click

Opening the top-right "Share a link" dialog used to save a session right away, so
just looking at the dialog left an unused link in the user's session list.  The
dialog now explains what the link is and offers one "Create link & copy" button
that saves the session and copies the URL in a single step.

The random name for a machine-generated session is now made client-side and sent
with the request, so there is one convention in one place: a leading underscore
(kept verbatim by the short-link encoder, so /s/<user>/_XXXXXXXX stays clean)
plus eight URL-safe characters.  hgSession.c no longer auto-names; a logged-in
save with no name is an error, which is what the callers already guarantee.
refs #10138

diff --git src/hg/js/hgSession.js src/hg/js/hgSession.js
index a1dda41235a..1cba1a3abdd 100644
--- src/hg/js/hgSession.js
+++ src/hg/js/hgSession.js
@@ -35,39 +35,40 @@
 
 var sessData = null;   // set in sessionBuild: {config, sessions}
 var sessDt = null;     // the DataTable API
 var sessSelectMode = false;   // bulk-select (checkbox column) shown?
 
 function sessEnc(s) {
     // HTML-escape via the shared utils.js helper (escapes quotes too, so it is attribute-safe).
     return (typeof htmlEncode === 'function') ? htmlEncode(String(s == null ? '' : s)) : String(s);
 }
 
 function sessNum(n) {
     return (typeof commify === 'function') ? commify(n) : String(n);
 }
 
 function sessRandomShareName() {
-    // Mirror the server's auto/anonymous share-name convention ("share_" + 8 URL-safe alphanumeric
-    // chars).  hgSession.c's doSaveSessionJson generates the same style server-side for the top-right
-    // "Share a link"; we generate it here so the confirm dialog can show the name before saving.
+    // Auto-name convention for machine-generated session names: a leading "_" (which marks the name
+    // as internally generated, and is kept verbatim by the short-link encoder) followed by 8 URL-safe
+    // alphanumeric chars.  This is the single source of the convention: the top-right "Share a link"
+    // menu (topLinks.js) and hgSession.c both defer to a name generated here.
     var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
     var s = '';
     for (var i = 0; i < 8; i++) {
         s += chars.charAt(Math.floor(Math.random() * chars.length));
     }
-    return 'share_' + s;
+    return '_' + s;
 }
 
 function sessMbpPos(pos) {
     // Shorten a position to megabases to save horizontal space:
     // "chr7:155799529-155812871" -> "chr7:155.80-155.81 Mbp".  Falls back to the raw string
     // if it doesn't parse.
     var m = /^(.+):([0-9,]+)-([0-9,]+)$/.exec(String(pos));
     if (!m) { return String(pos); }
     var s = parseInt(m[2].replace(/,/g, ''), 10);
     var e = parseInt(m[3].replace(/,/g, ''), 10);
     if (isNaN(s) || isNaN(e)) { return String(pos); }
     return m[1] + ':' + (s / 1e6).toFixed(2) + '-' + (e / 1e6).toFixed(2) + ' Mbp';
 }
 
 function sessMsg(text, cls) {
@@ -420,31 +421,31 @@
 }
 
 // Build the base params for an action on a given session (decoded name; the CGI re-encodes it).
 function sessActParams(action, row) {
     var p = {};
     p[action] = '1';
     p[SESS_P.oldName] = row.name;
     return p;
 }
 
 // ---- Save current view ---------------------------------------------------
 
 function sessDoSave() {
     var name = document.getElementById('sessSaveName').value.trim();
     if (!name) {
-        // Empty name: offer to save under a server-style random "share_XXXXXXXX" name, after
+        // Empty name: offer to save under a random internal "_XXXXXXXX" name, after
         // confirming the user really meant to leave it blank.
         var rand = sessRandomShareName();
         sessConfirm({
             title: 'Save without a name?',
             bodyHtml: 'You left the session name empty. Your session will be saved under the ' +
                 'randomly generated name <b>' + sessEnc(rand) + '</b>.<br><br>You can also create ' +
                 'these quick share links any time from the <b>Share a link</b> option at the top ' +
                 'right of every Genome Browser page.',
             okLabel: 'Save session',
             onOk: function() { sessModalClose(); sessDoSaveWithName(rand); }
         });
         return;
     }
     sessDoSaveWithName(name);
 }