Showing 1 changed files with 30 additions and 8 deletions
+30 -8
scripts/host_manager.pl
@@ -2463,11 +2463,14 @@ sub app_html {
2463 2463
     .debug-controls { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; width: 100%; }
2464 2464
     .debug-meta { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
2465 2465
     .debug-table-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 8px; padding: 10px; border-top: 1px solid var(--line); }
2466
-    .debug-table-card { display: grid; align-content: center; justify-items: start; gap: 5px; min-height: 58px; padding: 9px 10px; text-align: left; background: #fff; }
2466
+    .debug-table-card { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 6px; min-height: 58px; padding: 8px; border: 1px solid var(--line); border-radius: 6px; background: #fff; }
2467 2467
     .debug-table-card:hover { border-color: #9fb7e9; background: #f8fbff; }
2468 2468
     .debug-table-card.active { border-color: var(--accent); background: #e8f0fe; box-shadow: inset 0 0 0 1px var(--accent); }
2469
+    .debug-table-card-main { display: grid; align-content: center; justify-items: start; gap: 5px; min-width: 0; min-height: 42px; width: 100%; padding: 4px 6px; border: 0; background: transparent; text-align: left; }
2470
+    .debug-table-card-main:hover { background: transparent; }
2469 2471
     .debug-table-card-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); font-weight: 700; }
2470 2472
     .debug-table-card-rows { color: var(--muted); font-size: 12px; }
2473
+    .debug-table-copy { min-width: 34px; width: 34px; justify-content: center; padding: 7px; color: var(--muted); }
2471 2474
     .debug-section { display: grid; gap: 16px; }
2472 2475
     .host-tools { display: flex; align-items: center; justify-content: flex-end; gap: 8px; min-width: 0; }
2473 2476
     .host-tools input { max-width: 240px; }
@@ -3012,7 +3015,7 @@ sub app_html {
3012 3015
         ['rows', data.counts ? data.counts.rows : tables.reduce((total, table) => total + Number(table.rows || 0), 0)],
3013 3016
       ].map(([k, v]) => `<span class="stat">${escapeHtml(k)}: ${escapeHtml(String(v))}</span>`).join('');
3014 3017
       $('debug-db-meta').textContent = data.database || '';
3015
-      renderDebugTableCards(tables, selected);
3018
+      renderDebugTableCards(tables, selected, data.database || '');
3016 3019
       if (selected) {
3017 3020
         await renderDebugTable(selected);
3018 3021
       } else {
@@ -3020,14 +3023,18 @@ sub app_html {
3020 3023
       }
3021 3024
     }
3022 3025
 
3023
-    function renderDebugTableCards(tables, selected) {
3026
+    function renderDebugTableCards(tables, selected, database) {
3024 3027
       $('debug-db-tables').innerHTML = tables.length
3025 3028
         ? tables.map(table => {
3026 3029
             const active = table.name === selected;
3027
-            return `<button type="button" class="debug-table-card ${active ? 'active' : ''}" data-debug-table="${escapeHtml(table.name)}" aria-pressed="${active ? 'true' : 'false'}">
3028
-              <span class="debug-table-card-name mono">${escapeHtml(table.name)}</span>
3029
-              <span class="debug-table-card-rows">${escapeHtml(String(table.rows || 0))} rows</span>
3030
-            </button>`;
3030
+            const ref = debugTableReference(database, table.name);
3031
+            return `<div class="debug-table-card ${active ? 'active' : ''}">
3032
+              <button type="button" class="debug-table-card-main" data-debug-table="${escapeHtml(table.name)}" aria-pressed="${active ? 'true' : 'false'}">
3033
+                <span class="debug-table-card-name mono">${escapeHtml(table.name)}</span>
3034
+                <span class="debug-table-card-rows">${escapeHtml(String(table.rows || 0))} rows</span>
3035
+              </button>
3036
+              <button type="button" class="debug-table-copy" data-debug-table-ref="${escapeHtml(ref)}" title="${escapeHtml(ref)}" aria-label="Copy full table reference for ${escapeHtml(table.name)}">Ref</button>
3037
+            </div>`;
3031 3038
           }).join('')
3032 3039
         : '<div class="ca-empty muted">No database tables found.</div>';
3033 3040
       document.querySelectorAll('[data-debug-table]').forEach(button => {
@@ -3035,13 +3042,28 @@ sub app_html {
3035 3042
           if (!isAuthLost(e)) msg(e.message);
3036 3043
         }));
3037 3044
       });
3045
+      document.querySelectorAll('[data-debug-table-ref]').forEach(button => {
3046
+        button.addEventListener('click', async () => {
3047
+          try {
3048
+            await copyText(button.dataset.debugTableRef || '');
3049
+            msg('table reference copied');
3050
+          } catch (e) {
3051
+            msg('copy failed');
3052
+          }
3053
+        });
3054
+      });
3055
+    }
3056
+
3057
+    function debugTableReference(database, tableName) {
3058
+      return `sqlite:${database || ''}#${tableName || ''}`;
3038 3059
     }
3039 3060
 
3040 3061
     async function selectDebugTable(tableName) {
3041 3062
       state.debugTable = tableName || '';
3042 3063
       document.querySelectorAll('[data-debug-table]').forEach(button => {
3043 3064
         const active = button.dataset.debugTable === state.debugTable;
3044
-        button.classList.toggle('active', active);
3065
+        const card = button.closest('.debug-table-card');
3066
+        if (card) card.classList.toggle('active', active);
3045 3067
         button.setAttribute('aria-pressed', active ? 'true' : 'false');
3046 3068
       });
3047 3069
       if (state.debugTable) await renderDebugTable(state.debugTable);