From 34d5f66bc26a710bcae8826c56d332ebf40ea51f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=91=D0=BE=D0=B1?= =?UTF-8?q?=D1=8B=D1=80=D0=B5=D0=B2?= Date: Sat, 25 Apr 2026 19:30:42 +0300 Subject: [PATCH] =?UTF-8?q?fix(ui):=20router=20Test/Pull/Del=20=E2=80=94?= =?UTF-8?q?=20broken=20onclick=20from=20JSON=20quotes;=20use=20data-*=20de?= =?UTF-8?q?legation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made-with: Cursor --- server/templates/index.html | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/server/templates/index.html b/server/templates/index.html index c5c6ee7..9ea7ddd 100644 --- a/server/templates/index.html +++ b/server/templates/index.html @@ -350,17 +350,35 @@ async function importAndPush(){ await importFiles(); setTimeout(pushAll,300); } async function loadExport(){ document.getElementById('dc-export').value=await(await fetch('/hydra/domain.conf')).text(); document.getElementById('il-export').value=await(await fetch('/hydra/ip.list')).text(); } // ── ROUTERS ─────────────────────────────────────────────────────────────── +function _escHtml(s){ return String(s==null?'':s).replace(/&/g,'&').replace(//g,'>'); } +(function _bindRouterList(){ + const box=document.getElementById('routers-list'); + if(!box||box.dataset.actBind==='1') return; + box.dataset.actBind='1'; + box.addEventListener('click',async (e)=>{ + const b=e.target.closest('button[data-r-act]'); + if(!b) return; + const n=decodeURIComponent(b.getAttribute('data-router')||''); + const act=b.getAttribute('data-r-act'); + if(act==='test') await testRouter(n); + else if(act==='pull') await pullRouter(n); + else if(act==='del') await delRouter(n); + }); +})(); async function loadRouters(){ const R=await(await fetch('/api/routers')).json(); const el=document.getElementById('routers-list'); if(!Object.keys(R).length){ el.innerHTML='Роутеры не добавлены'; return; } - el.innerHTML=Object.entries(R).map(([n,c])=>`
-
${n} — ${c.ip||'—'}
+ el.innerHTML=Object.entries(R).map(([n,c])=>{ + const enc=encodeURIComponent(n); + return `
+
${_escHtml(n)} — ${_escHtml(c.ip||'—')}
- - - -
`).join(''); + + + +
`; + }).join(''); } async function addRouter(){ const n=document.getElementById('r-name').value.trim(); if(!n)return; const b={ip:document.getElementById('r-ip').value.trim(),user:document.getElementById('r-user').value||'root',password:document.getElementById('r-pass').value}; try{ await fetch('/api/routers/'+encodeURIComponent(n),{method:'POST',headers:authHdr(),body:JSON.stringify(b)}); sm('rm','ok','✅ '+n); loadRouters(); }catch(e){sm('rm','err','❌ '+e)} } async function delRouter(n){ if(!confirm('Удалить '+n+'?'))return; await fetch('/api/routers/'+encodeURIComponent(n),{method:'DELETE',headers:{'X-Admin-Password':getPass()}}); loadRouters(); }