修复Kanban: 恢复筛选器+卡片+指派者完整视图
This commit is contained in:
@@ -102,7 +102,23 @@ async function fM(){try{var r=await fetch('/api/monitor'),d=await r.json();var h
|
|||||||
async function fT(){try{var r=await fetch('/api/todos'),d=await r.json();fill('todos','<span>'+(d.todos.length)+' records</span>')}catch(e){}}
|
async function fT(){try{var r=await fetch('/api/todos'),d=await r.json();fill('todos','<span>'+(d.todos.length)+' records</span>')}catch(e){}}
|
||||||
async function fE(){try{var r=await fetch('/api/metagrowth'),d=await r.json();fill('meta','fixes: '+(d.total_fixes||0)+' commits: '+(d.commit_count||0))}catch(e){}}
|
async function fE(){try{var r=await fetch('/api/metagrowth'),d=await r.json();fill('meta','fixes: '+(d.total_fixes||0)+' commits: '+(d.commit_count||0))}catch(e){}}
|
||||||
async function fF(){try{var r=await fetch('/api/expected'),d=await r.json();var ok=0;for(var i=0;i<d.expected.length;i++){var e=d.expected[i],a=d.actual[e.name]||'',cmp=(e.expected.indexOf('running')===0&&a==='running')||(e.expected.indexOf('scheduled')===0&&(a==='scheduled'||a==='running'));if(cmp)ok++}fill('exp',ok+'/'+d.expected.length+' compliant')}catch(e){}}
|
async function fF(){try{var r=await fetch('/api/expected'),d=await r.json();var ok=0;for(var i=0;i<d.expected.length;i++){var e=d.expected[i],a=d.actual[e.name]||'',cmp=(e.expected.indexOf('running')===0&&a==='running')||(e.expected.indexOf('scheduled')===0&&(a==='scheduled'||a==='running'));if(cmp)ok++}fill('exp',ok+'/'+d.expected.length+' compliant')}catch(e){}}
|
||||||
async function fK(){try{var r=await fetch('/api/kanban'),d=await r.json(),n=(d.tasks||[]).length;fill('kanban',n?'<span>'+n+' tasks</span>':'<span class="dim">No tasks</span>')}catch(e){}}
|
async function fK(){try{var r=await fetch('/api/kanban'),d=await r.json();var tasks=d.tasks||[];var s=document.getElementById('kf-status');var a=document.getElementById('kf-assignee');var fs=s?s.value:'';var fa=a?a.value:'';
|
||||||
|
if(tasks.length==0){fill('kanban','<div style=text-align:center;padding:40px;color:var(--dim)>No tasks</div>');return}
|
||||||
|
var html='<div style=display:flex;gap:8px;margin-bottom:16px>';html+='<select id=kf-status style=background:var(--card);border:1px solid var(--border);border-radius:5px;padding:6px 10px;color:var(--text);font-size:12px><option value="">All Status</option><option value=ready>Ready</option><option value=progress>In Progress</option><option value=blocked>Blocked</option><option value=done>Done</option></select>';
|
||||||
|
html+='<select id=kf-assignee style=background:var(--card);border:1px solid var(--border);border-radius:5px;padding:6px 10px;color:var(--text);font-size:12px><option value="">All</option><option value=mohe>mohe</option><option value=zhiwei>zhiwei</option><option value=xxm>xxm</option><option value=xiaoguo>xiaoguo</option></select>';
|
||||||
|
html+='<span style=color:var(--dim);font-size:12px;align-self:center>'+tasks.length+' tasks</span></div>';
|
||||||
|
var filtered=tasks;if(fs)filtered=filtered.filter(function(t){return t.status===fs});if(fa)filtered=filtered.filter(function(t){return t.assignee===fa});
|
||||||
|
var colors={ready:'var(--green)',progress:'var(--yellow)',blocked:'var(--red)',done:'var(--dim)'};var labels={ready:'Ready',progress:'In Progress',blocked:'Blocked',done:'Done'};
|
||||||
|
html+=filtered.map(function(t){return'<div style="background:var(--card);border:1px solid var(--border);border-radius:8px;padding:12px 16px;margin-bottom:8px;border-left:3px solid '+(colors[t.status]||'var(--dim)')+'" id=kc-'+t.id+'"><div style=font-size:14px;font-weight:600>'+esc(t.title)+'</div><div style=display:flex;gap:12px;font-size:11px;color:var(--dim);margin-bottom:6px>'
|
||||||
|
+'<span style="display:inline-block;padding:1px 6px;border-radius:3px;font-size:10px;font-weight:600;background:'+(colors[t.status]||'var(--dim)')+';color:#000">'+(labels[t.status]||t.status)+'</span>'
|
||||||
|
+'<span>'+(t.assignee?'@'+esc(t.assignee):'')+'</span>'
|
||||||
|
+'<span>'+(t.created_at?new Date(t.created_at*1000).toLocaleDateString():'')+'</span></div>'
|
||||||
|
+(t.body?'<div style=font-size:12px;color:var(--dim);white-space:pre-wrap;max-height:60px;overflow:hidden;cursor:pointer onclick="this.classList.toggle(\'expanded\');if(this.style.maxHeight!==\'none\')this.style.maxHeight=\'none\';else this.style.maxHeight=\'60px\'">'+esc(t.body)+'</div>':'')
|
||||||
|
+'</div>'}).join('');
|
||||||
|
fill('kanban',html);
|
||||||
|
var es=document.getElementById('kf-status');var ea=document.getElementById('kf-assignee');
|
||||||
|
if(es&&!s)es.value=fs;if(ea&&!a)ea.value=fa;
|
||||||
|
if(es)es.onchange=fK;if(ea)ea.onchange=fK;}catch(e){}}
|
||||||
async function fI(){try{ var r=await fetch('/api/platform'),d=await r.json(); var h='<div class="ps"><h2>Platform</h2><div class="psv">'; for(var i=0;i<d.length;i++){h+='<div class="i"><span class="d '+(d[i].status==='running'?'ok':'stopped')+'"></span>'+esc(d[i].name)+'</div>';} h+='</div></div>'; try{var r2=await fetch('/api/ejabberd'),e=await r2.json();var ea=e.alive||e.xmpp_bot_connected; h+='<div class="ps"><h2>Ejabberd</h2><div class="psv"><div class="i"><span class="d '+(ea?'ok':'stopped')+'"></span>'+(ea?'ALIVE':'DOWN')+'</div></div></div>';}catch(e2){} fill('infra',h); /* EasyTier section */ try{var r3=await fetch('/api/easytier'),e3=await r3.json(),s=e3.status||{}; var et=document.createElement('div');et.className='ps';et.style.marginTop='16px'; var av=(e3.virtual_ips||{});var wip=av.windows||'';var tip=av['246']||''; et.innerHTML='<h2>EasyTier VPN</h2><div class=psv><div class=i><span class=d id=et-w></span>Windows <span id=et-w-ip>'+wip+'</span></div><div class=i><span class=d id=et-246></span>246 <span id=et-246-ip>'+tip+'</span></div></div><div style=margin-top:8px;display:flex;gap:8px;align-items:center><button class="btn s" id=btn-et-on>Turn On</button><button class="btn x" id=btn-et-off>Turn Off</button><span id=et-status style=font-size:12px;color:var(--dim)>-</span></div>'; var ci=document.getElementById('ct-infra');if(ci)ci.appendChild(et); var e1=document.getElementById('et-w');if(e1)e1.className='d '+(s.windows==='running'?'ok':'stopped'); var e2=document.getElementById('et-246');if(e2)e2.className='d '+(s['246']==='running'?'ok':'stopped'); var allRun=Object.values(s).every(function(v){return v==='running'||v==='pending'}); var ob=document.getElementById('btn-et-on');var ofb=document.getElementById('btn-et-off');var stx=document.getElementById('et-status'); if(ob){ob.disabled=allRun;ob.onclick=function(){fetch('/api/easytier/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'start'})}).then(function(){setTimeout(fI,500)}).catch(function(e){toast('ET Fail','err')})};} if(ofb){ofb.disabled=!allRun;ofb.onclick=function(){fetch('/api/easytier/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'stop'})}).then(function(){setTimeout(fI,500)}).catch(function(e){toast('ET Fail','err')})};} if(stx)stx.textContent=allRun?'Connected':'Off';}catch(e3){} /* RDP section */ try{var r4=await fetch('/api/rdp'),e4=await r4.json(); var rd=document.createElement('div');rd.className='ps';rd.style.marginTop='16px'; rd.innerHTML='<h2>RDP Remote Desktop</h2><div class=psv><div class=i><span class=d id=rdp-st></span>RDP <span id=rdp-info>'+esc(e4.public_endpoint||'')+'</span></div><div class=i><span class=d id=rdp-tun></span>Tunnel</div></div><div style=margin-top:8px;display:flex;gap:8px;align-items:center><button class="btn s" id=btn-rdp-on>Enable</button><button class="btn x" id=btn-rdp-off>Disable</button><span id=rdp-status-txt style=font-size:12px;color:var(--dim)>-</span></div>'; var ci2=document.getElementById('ct-infra');if(ci2)ci2.appendChild(rd); var ee1=document.getElementById('rdp-st');if(ee1)ee1.className='d '+(e4.rdp_enabled?'ok':'stopped'); var ee2=document.getElementById('rdp-tun');if(ee2)ee2.className='d '+(e4.tunnel_running?'ok':'stopped'); var fOn=e4.rdp_enabled&&e4.tunnel_running; var ob2=document.getElementById('btn-rdp-on');var ofb2=document.getElementById('btn-rdp-off');var stx2=document.getElementById('rdp-status-txt'); if(ob2){ob2.disabled=fOn;ob2.onclick=function(){fetch('/api/rdp/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'start'})}).then(function(){setTimeout(fI,500)}).catch(function(e){toast('RDP Fail','err')})};} if(ofb2){ofb2.disabled=!fOn;ofb2.onclick=function(){fetch('/api/rdp/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'stop'})}).then(function(){setTimeout(fI,500)}).catch(function(e){toast('RDP Fail','err')})};} if(stx2)stx2.textContent=fOn?'Connected':e4.rdp_enabled?'Tunnel pending':'Disconnected';}catch(e4){} }catch(e){}}
|
async function fI(){try{ var r=await fetch('/api/platform'),d=await r.json(); var h='<div class="ps"><h2>Platform</h2><div class="psv">'; for(var i=0;i<d.length;i++){h+='<div class="i"><span class="d '+(d[i].status==='running'?'ok':'stopped')+'"></span>'+esc(d[i].name)+'</div>';} h+='</div></div>'; try{var r2=await fetch('/api/ejabberd'),e=await r2.json();var ea=e.alive||e.xmpp_bot_connected; h+='<div class="ps"><h2>Ejabberd</h2><div class="psv"><div class="i"><span class="d '+(ea?'ok':'stopped')+'"></span>'+(ea?'ALIVE':'DOWN')+'</div></div></div>';}catch(e2){} fill('infra',h); /* EasyTier section */ try{var r3=await fetch('/api/easytier'),e3=await r3.json(),s=e3.status||{}; var et=document.createElement('div');et.className='ps';et.style.marginTop='16px'; var av=(e3.virtual_ips||{});var wip=av.windows||'';var tip=av['246']||''; et.innerHTML='<h2>EasyTier VPN</h2><div class=psv><div class=i><span class=d id=et-w></span>Windows <span id=et-w-ip>'+wip+'</span></div><div class=i><span class=d id=et-246></span>246 <span id=et-246-ip>'+tip+'</span></div></div><div style=margin-top:8px;display:flex;gap:8px;align-items:center><button class="btn s" id=btn-et-on>Turn On</button><button class="btn x" id=btn-et-off>Turn Off</button><span id=et-status style=font-size:12px;color:var(--dim)>-</span></div>'; var ci=document.getElementById('ct-infra');if(ci)ci.appendChild(et); var e1=document.getElementById('et-w');if(e1)e1.className='d '+(s.windows==='running'?'ok':'stopped'); var e2=document.getElementById('et-246');if(e2)e2.className='d '+(s['246']==='running'?'ok':'stopped'); var allRun=Object.values(s).every(function(v){return v==='running'||v==='pending'}); var ob=document.getElementById('btn-et-on');var ofb=document.getElementById('btn-et-off');var stx=document.getElementById('et-status'); if(ob){ob.disabled=allRun;ob.onclick=function(){fetch('/api/easytier/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'start'})}).then(function(){setTimeout(fI,500)}).catch(function(e){toast('ET Fail','err')})};} if(ofb){ofb.disabled=!allRun;ofb.onclick=function(){fetch('/api/easytier/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'stop'})}).then(function(){setTimeout(fI,500)}).catch(function(e){toast('ET Fail','err')})};} if(stx)stx.textContent=allRun?'Connected':'Off';}catch(e3){} /* RDP section */ try{var r4=await fetch('/api/rdp'),e4=await r4.json(); var rd=document.createElement('div');rd.className='ps';rd.style.marginTop='16px'; rd.innerHTML='<h2>RDP Remote Desktop</h2><div class=psv><div class=i><span class=d id=rdp-st></span>RDP <span id=rdp-info>'+esc(e4.public_endpoint||'')+'</span></div><div class=i><span class=d id=rdp-tun></span>Tunnel</div></div><div style=margin-top:8px;display:flex;gap:8px;align-items:center><button class="btn s" id=btn-rdp-on>Enable</button><button class="btn x" id=btn-rdp-off>Disable</button><span id=rdp-status-txt style=font-size:12px;color:var(--dim)>-</span></div>'; var ci2=document.getElementById('ct-infra');if(ci2)ci2.appendChild(rd); var ee1=document.getElementById('rdp-st');if(ee1)ee1.className='d '+(e4.rdp_enabled?'ok':'stopped'); var ee2=document.getElementById('rdp-tun');if(ee2)ee2.className='d '+(e4.tunnel_running?'ok':'stopped'); var fOn=e4.rdp_enabled&&e4.tunnel_running; var ob2=document.getElementById('btn-rdp-on');var ofb2=document.getElementById('btn-rdp-off');var stx2=document.getElementById('rdp-status-txt'); if(ob2){ob2.disabled=fOn;ob2.onclick=function(){fetch('/api/rdp/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'start'})}).then(function(){setTimeout(fI,500)}).catch(function(e){toast('RDP Fail','err')})};} if(ofb2){ofb2.disabled=!fOn;ofb2.onclick=function(){fetch('/api/rdp/toggle',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({action:'stop'})}).then(function(){setTimeout(fI,500)}).catch(function(e){toast('RDP Fail','err')})};} if(stx2)stx2.textContent=fOn?'Connected':e4.rdp_enabled?'Tunnel pending':'Disconnected';}catch(e4){} }catch(e){}}
|
||||||
async function fH(){try{var r=await fetch('/api/prd'),d=await r.json();if(!d.ok||!d.content){fill('prd','Failed');return}var el=document.getElementById('ct-prd');var sp=el?el.querySelector('div')?el.querySelector('div').scrollTop:0:0;fill('prd','<div style=max-height:600px;overflow-y:auto;background:var(--bg);padding:16px;border-radius:6px>'+mdRender(d.content)+'</div>');var el2=document.getElementById('ct-prd');if(el2&&sp){setTimeout(function(){(el2.querySelector('div')||el2).scrollTop=sp},0)}}catch(e){fill('prd','Error')}}async function fTree(){try{var r=await fetch('/api/services'),d=await r.json();if(!d.services||!d.services.length){fill('tree','No data');return}
|
async function fH(){try{var r=await fetch('/api/prd'),d=await r.json();if(!d.ok||!d.content){fill('prd','Failed');return}var el=document.getElementById('ct-prd');var sp=el?el.querySelector('div')?el.querySelector('div').scrollTop:0:0;fill('prd','<div style=max-height:600px;overflow-y:auto;background:var(--bg);padding:16px;border-radius:6px>'+mdRender(d.content)+'</div>');var el2=document.getElementById('ct-prd');if(el2&&sp){setTimeout(function(){(el2.querySelector('div')||el2).scrollTop=sp},0)}}catch(e){fill('prd','Error')}}async function fTree(){try{var r=await fetch('/api/services'),d=await r.json();if(!d.services||!d.services.length){fill('tree','No data');return}
|
||||||
var tree={name:'System',children:[]};var map={};d.services.forEach(function(s){map[s.name]=s;if(!s.depends_on||!s.depends_on.length){tree.children.push(s)}else{s._parents=s.depends_on}});
|
var tree={name:'System',children:[]};var map={};d.services.forEach(function(s){map[s.name]=s;if(!s.depends_on||!s.depends_on.length){tree.children.push(s)}else{s._parents=s.depends_on}});
|
||||||
|
|||||||
Reference in New Issue
Block a user