let currentDb = ''; let currentTable = ''; let openedDb = ''; function getCsrfToken() { return document.querySelector('meta[name="csrf-token"]')?.content || ''; } function filterTables(inp) { const q = inp.value.toLowerCase(); const body = inp.closest('.pma-accordion-body'); if (body) { body.querySelectorAll('.pma-table-item').forEach(el => { el.style.display = !q || (el.dataset.tbl || '').includes(q) ? '' : 'none'; }); } } function filterSidebar(q) { document.querySelectorAll('.pma-accordion-item').forEach(el => { el.style.display = el.textContent.toLowerCase().includes(q.toLowerCase()) ? '' : 'none'; }); } function toggleDb(db) { const item = document.querySelector(`.pma-accordion-item[data-db="${db.replace(/"/g,'\\"')}"]`); if (!item) return; const body = item.querySelector('.pma-accordion-body'); const header = item.querySelector('.pma-accordion-header'); const chevron = item.querySelector('.pma-chevron'); if (item.classList.contains('expanded')) { item.classList.remove('expanded'); body.style.maxHeight = '0'; return; } document.querySelectorAll('.pma-accordion-item.expanded').forEach(el => { el.classList.remove('expanded'); el.querySelector('.pma-accordion-body').style.maxHeight = '0'; }); item.classList.add('expanded'); currentDb = db; if (body.querySelector('.pma-table-item')) { body.style.maxHeight = body.scrollHeight + 'px'; return; } body.querySelector('.pma-loading-tables').style.display = ''; body.style.maxHeight = '60px'; fetch('/servers/' + serverId + '/database', { method: 'POST', headers: {'Content-Type':'application/x-www-form-urlencoded','X-CSRF-Token':getCsrfToken()}, body: 'action=tables&db=' + encodeURIComponent(db) + '&_csrf_token=' + encodeURIComponent(getCsrfToken()), }) .then(r => r.json()) .then(data => { body.querySelector('.pma-loading-tables').style.display = 'none'; let html = '
'; (data.tables || []).forEach(t => { html += '
' + ' ' + escHtml(t.name) + ' ' + t.rows + ' rows
'; }); if (!html) html = '
No tables
'; body.innerHTML = html; body.style.maxHeight = body.scrollHeight + 'px'; }); } function selectTable(db, table) { currentDb = db; currentTable = table; document.getElementById('tabBrowse').style.display = ''; document.getElementById('tabStructure').style.display = ''; document.querySelectorAll('.pma-tab').forEach(t=>t.classList.remove('active')); document.getElementById('tabStructure').classList.add('active'); showPanel('structure'); loadStructure(db, table); } function loadStructure(db, table) { const panel = document.getElementById('pmaStructure'); panel.innerHTML = '
Loading structure...
'; fetch('/servers/' + serverId + '/database', { method:'POST', headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-Token':getCsrfToken()}, body:'action=structure&db='+encodeURIComponent(db)+'&table='+encodeURIComponent(table)+'&_csrf_token='+encodeURIComponent(getCsrfToken()), }).then(r=>r.json()).then(d=>{ if (!d.success||!d.columns) return; let html='
' +'

'+escHtml(table)+'

' +''+d.columns.length+' columns' +'' +'' +'
'; html+='
'; d.columns.forEach((c,i)=>{ html+='' +'' +''; }); html+='
#FieldTypeCollationNullKeyDefaultExtra
'+(i+1)+''+escHtml(c.field)+''+escHtml(c.type)+''+escHtml(c.collation)+''+escHtml(c.null)+''+escHtml(c.key)+''+(c.default??'NULL')+''+escHtml(c.extra)+'
'; panel.innerHTML=html; }); } function browseTable(db, table) { currentDb=db; currentTable=table; document.getElementById('tabBrowse').style.display=''; document.getElementById('tabStructure').style.display=''; document.querySelectorAll('.pma-tab').forEach(t=>t.classList.remove('active')); document.getElementById('tabBrowse').classList.add('active'); showPanel('browse'); loadBrowse(db,table,1); } function loadBrowse(db,table,page) { const panel=document.getElementById('pmaBrowse'); const inputs=document.querySelectorAll('.pma-fi'); let filters=''; if(inputs.length){ const p={}; inputs.forEach(inp=>{if(inp.value.trim())p[inp.dataset.col]=inp.value.trim()}); const s=new URLSearchParams(p).toString(); if(s)filters='&'+s; } panel.innerHTML='
Loading...
'; let body='action=browse&db='+encodeURIComponent(db)+'&table='+encodeURIComponent(table)+'&page='+page+filters+'&_csrf_token='+encodeURIComponent(getCsrfToken()); fetch('/servers/' + serverId + '/database',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-Token':getCsrfToken()},body}) .then(r=>r.json()).then(d=>{ if(!d.success)return; const tp=Math.ceil(d.total/d.per_page); let html='
' +'

'+escHtml(table)+'

' +''+d.total+' rows
'; html+='
'; html+='
'; d.columns.forEach(c=>{html+=''}); html+=''; d.columns.forEach(c=>{ const cv=new URLSearchParams(filters.replace(/^&/,'')).get(c)||''; html+=''; }); html+=''; d.rows.forEach(row=>{ html+=''; row.forEach(val=>{html+=''}); html+=''; }); html+='
'+escHtml(c)+'
'+escHtml(String(val).substring(0,80))+'
'; html+='
'; html+=''; html+=''; if(tp>1){ html+=''; for(let p=1;p<=tp&&p<=10;p++)html+=''; if(tp>10)html+='...'; } html+='
'; panel.innerHTML=html; }); } function clearBrowseFilters(db,table){ document.querySelectorAll('.pma-fi').forEach(inp=>inp.value=''); loadBrowse(db,table,1); } function loadUsers() { showPanel('users'); document.getElementById('tabUsers').style.display=''; const panel=document.getElementById('pmaUsers'); panel.innerHTML='
Loading users...
'; fetch('/servers/' + serverId + '/database',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-Token':getCsrfToken()},body:'action=users&_csrf_token='+encodeURIComponent(getCsrfToken())}) .then(r=>r.json()).then(d=>{ let html='
' +'

Database Users

' +''+(d.users?.length||0)+' users' +'' +'
'; html+='
'; (d.users||[]).forEach(u=>{ const dbList=(d.grants||[]).filter(g=>g.user===u.user&&g.host===u.host).map(g=>g.db).join(', '); html+='' +''; }); html+='
UserHostDatabasesExpiredActions
'+escHtml(u.user)+''+escHtml(u.host)+''+(dbList||'-')+''+escHtml(u.expired)+'' +' ' +'' +'
'; panel.innerHTML=html; }); } function showCreateUser() { const panel=document.getElementById('pmaUsers'); let html='
' +'

Create User

' +'' +'
' +'

Account

' +'
' +'
' +'
' +'

Database Access

' +'
'; databases.forEach(function(dbname) { if (dbname !== 'information_schema' && dbname !== 'performance_schema' && dbname !== 'mysql' && dbname !== 'sys') { html+=''; } }); html+='
' +'

Privileges

' +'
'; ['ALL PRIVILEGES','SELECT','INSERT','UPDATE','DELETE','CREATE','DROP','ALTER','INDEX','CREATE VIEW','SHOW VIEW','CREATE ROUTINE','ALTER ROUTINE','EXECUTE','LOCK TABLES','REFERENCES','EVENT','TRIGGER'].forEach(function(p){ var checked = p === 'ALL PRIVILEGES' ? ' checked' : ''; html+=''; }); html+='
' +'
' +'' +'
'; panel.innerHTML=html; } function doCreateUser() { const user=document.getElementById('nuUser').value; const pass=document.getElementById('nuPass').value; const host=document.getElementById('nuHost').value||'localhost'; if(!user||!pass){showToast('error','Username and password required');return;} const privs=[]; document.querySelectorAll('.nuPriv:checked').forEach(cb=>privs.push(cb.value)); const grantPrivs = privs.includes('ALL PRIVILEGES') ? 'ALL PRIVILEGES' : privs.join(','); fetch('/servers/' + serverId + '/database',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-Token':getCsrfToken()},body: 'action=create_user&new_user='+encodeURIComponent(user)+'&new_pass='+encodeURIComponent(pass)+'&new_host='+encodeURIComponent(host)+'&_csrf_token='+encodeURIComponent(getCsrfToken())}) .then(r=>r.json()).then(d=>{ showToast(d.success?'success':'error',d.message); if(d.success){ const dbs=[]; document.querySelectorAll('.nuDbCheck:checked').forEach(cb=>dbs.push(cb.value)); if(dbs.length>0){ let cnt=0; dbs.forEach(db=>{ fetch('/servers/' + serverId + '/database',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-Token':getCsrfToken()},body:'action=grant&grant_user='+encodeURIComponent(user)+'&grant_db='+encodeURIComponent(db)+'&grant_host='+encodeURIComponent(host)+'&grant_privs='+encodeURIComponent(grantPrivs)+'&_csrf_token='+encodeURIComponent(getCsrfToken())}) .then(r2=>r2.json()).then(g=>{ cnt++; if(cnt===dbs.length)loadUsers(); }); }); }else{loadUsers();} } }); } function showEditUser(user, host) { const panel = document.getElementById('pmaUsers'); panel.innerHTML='
' +'

Change Password

' +''+escHtml(user)+' @ '+escHtml(host)+'' +'' +'
' +'
' +'
' +'
' +'' +'
'; } function doChangePass(user, host) { const pass = document.getElementById('epPass').value; if (!pass) { showToast('error','Password required'); return; } fetch('/servers/' + serverId + '/database',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-Token':getCsrfToken()}, body:'action=change_pass&target_user='+encodeURIComponent(user)+'&target_host='+encodeURIComponent(host)+'&new_pass='+encodeURIComponent(pass)+'&_csrf_token='+encodeURIComponent(getCsrfToken())}) .then(r=>r.json()).then(d=>{showToast(d.success?'success':'error',d.message);if(d.success)loadUsers()}); } function deleteUser(user, host) { if (!confirm('Delete user \''+user+'\'@\''+host+'\'?\nThis cannot be undone.')) return; fetch('/servers/' + serverId + '/database',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-Token':getCsrfToken()}, body:'action=drop_user&target_user='+encodeURIComponent(user)+'&target_host='+encodeURIComponent(host)+'&_csrf_token='+encodeURIComponent(getCsrfToken())}) .then(r=>r.json()).then(d=>{showToast(d.success?'success':'error',d.message);if(d.success)loadUsers()}); } function runSql() { const sql=document.getElementById('sqlInput').value; if(!sql)return; const rd=document.getElementById('sqlResult'); const rt=document.getElementById('sqlResultText'); rd.style.display='none'; fetch('/servers/' + serverId + '/database',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded','X-CSRF-Token':getCsrfToken()},body:'action=query&query='+encodeURIComponent(sql)+'&_csrf_token='+encodeURIComponent(getCsrfToken())}) .then(r=>r.json()).then(d=>{if(d.output){rt.textContent=d.output;rd.style.display='block'}else showToast('error',d.message||'No results')}); } function showPanel(id) { document.querySelectorAll('.pma-panel').forEach(p=>p.classList.remove('active')); document.getElementById('pma'+id.charAt(0).toUpperCase()+id.slice(1)).classList.add('active'); } function switchTab(tab) { document.querySelectorAll('.pma-tab').forEach(t=>t.classList.remove('active')); const map={browse:'pmaBrowse',structure:'pmaStructure',sql:'pmaSql',users:'pmaUsers'}; const el=document.getElementById('tab'+tab.charAt(0).toUpperCase()+tab.slice(1)); if(el)el.classList.add('active'); showPanel(tab); if(tab==='sql'){document.getElementById('pmaWelcome').classList.remove('active');document.getElementById('pmaSql').classList.add('active');} } document.getElementById('sqlInput').addEventListener('keydown',function(e){if((e.ctrlKey||e.metaKey)&&e.key==='Enter')runSql()}); function escHtml(s){const d=document.createElement('div');d.textContent=s;return d.innerHTML;}