0108f1eb54fdce9856131873059928583be0bacb
max
  Mon Aug 24 03:58:09 2026 -0700
hgSession: add a Last used column to the sessions table. refs #38157

diff --git src/hg/js/hgSession.js src/hg/js/hgSession.js
index 1229d32ab16..090936a3cb4 100644
--- src/hg/js/hgSession.js
+++ src/hg/js/hgSession.js
@@ -722,33 +722,34 @@
                       sessEnc(row.encName) + '">'; } },
             { title: 'Session', className: 'sessNameCol', data: 'name',
               render: function(d, type, row) {
                   return (type === 'display') ? sessNameCellHtml(row) : row.name; } },
             { title: 'Assembly', data: 'db',
               render: function(d, type, row) {
                   if (type !== 'display') { return row.db || ''; }
                   var html = sessEnc(row.db || 'n/a');
                   if (row.position) {
                       html += ' <span class="sessPos">' + sessEnc(sessCommifyPos(row.position)) +
                           '</span>';
                   }
                   return html; } },
             { title: 'Created', data: 'createdEpoch',
               render: function(d, type, row) {
-                  if (type !== 'display') { return row.createdEpoch; }
-                  return '<span title="Last used: ' + sessEnc(row.lastUse) + '">' +
-                      sessEnc(row.created) + '</span>'; } },
+                  return (type === 'display') ? sessEnc(row.created) : row.createdEpoch; } },
+            { title: 'Last used', data: 'lastUseEpoch',
+              render: function(d, type, row) {
+                  return (type === 'display') ? sessEnc(row.lastUse) : row.lastUseEpoch; } },
             { title: 'Views', data: 'useCount',
               render: function(d, type) { return (type === 'display') ? sessNum(d) : d; } },
             { title: 'Actions', className: 'sessActionsCol', data: null, orderable: false,
               searchable: false,
               render: function(d, type, row) { return (type === 'display') ? sessActionsHtml(row) : ''; } }
         ]
     });
 
     // Delegate the row action buttons.
     $('#sessionAppTable tbody').on('click', 'button[data-act]', function() {
         var act = this.getAttribute('data-act');
         var row = sessByEnc(this.getAttribute('data-enc'));
         if (!row) { return; }
         if (act === 'overwrite') { sessOpenOverwrite(row); }
         else if (act === 'share') { sessOpenShare(row); }
@@ -764,29 +765,30 @@
     selBtn.className = 'gbPill';
     selBtn.textContent = 'Select';
     selBtn.title = 'Select multiple sessions to delete them at once';
     document.querySelector('#sessionApp .sessToolbar').appendChild(selBtn);
     $(selBtn).on('click', sessToggleSelect);
     // Header "select all" toggles every checkbox on the current page.
     $('#sessionAppTable').on('change', '#sessSelAll', function() {
         $('#sessionAppTable tbody .sessSelChk').prop('checked', this.checked);
     });
 
     // Column-header tooltips (set title, then let utils.js convert to styled mouseovers).
     var tips = {
         'Session': 'Click a name to load that session in the Genome Browser',
         'Assembly': 'The genome assembly this session was saved on',
         'Created': 'When the session was first saved',
+        'Last used': 'When the session was last saved or loaded',
         'Views': 'How many times this session has been loaded',
         'Actions': 'Overwrite with your current view, share, edit, or delete'
     };
     $('#sessionAppTable thead th').each(function() {
         var t = tips[$(this).text().trim()];
         if (t) { $(this).attr('title', t); }
     });
 }
 
 $(document).ready(function() {
     if (typeof hgSessionData !== 'undefined' && document.getElementById('sessionApp')) {
         sessionBuild();
     }
 });