Files
HomeAgent/internal/plugins/webui/dashboard2.html

2 lines
7.6 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

function renderOneSettings(){let prefix=state.selectedSection+'.';let allKeys=Object.keys(state.settings||{});let filtered=allKeys.filter(k=>k===prefix.slice(0,-1)||k.startsWith(prefix));filtered.sort();let hideTopLlms=['core.llm.base_url','core.llm.model','core.llm.api_key','core.llm.adapter','core.llm.adapter_path','core.llm.thinking_enabled'];let sourceKeys=filtered.filter(k=>k.startsWith('core.llm.sources.'));let sourceMap={};sourceKeys.forEach(k=>{let parts=k.split('.');let srcName=parts[3];if(!sourceMap[srcName])sourceMap[srcName]={};sourceMap[srcName][k]=true});let mcpServerKeys=filtered.filter(k=>k.startsWith('plugin.mcp.servers.')&&k.split('.').length>=5);let mcpServerMap={};mcpServerKeys.forEach(k=>{let parts=k.split('.');let srvName=parts[3];if(!mcpServerMap[srvName])mcpServerMap[srvName]={};mcpServerMap[srvName][k]=true});let regularKeys=filtered.filter(k=>!k.startsWith('core.llm.sources.')&&hideTopLlms.indexOf(k)===-1&&!k.startsWith('plugin.mcp.servers.')&&k!=='plugin.mcp.servers');let html='<div class="settings-layout"><div class="settings-sidebar"></div><div class="settings-content">';if(regularKeys.length===0&&Object.keys(sourceMap).length===0&&Object.keys(mcpServerMap).length===0&&state.selectedSection!=='plugin.mcp'){html+='<div class="card"><h2>'+escHtml(state.selectedSection)+'</h2><p style="color:var(--text-muted)">暂无设置é¡?/p></div>'}else{regularKeys.forEach(k=>{let v=state.settings[k];let sv=typeof v==='object'?JSON.stringify(v):String(v);let m=state.meta?.[k];let label=m?.display_name||'å€?;let desc=m?.description||'';let typ=m?.type||'string';let ph=m?.placeholder||'';let opts=m?.options||[];let inpId='inp-'+k.replace(/\./g,'_');let inp='';if(typ==='bool'){let chk=sv==='true'?'checked':'';inp='<label style="display:flex;align-items:center;gap:8px;cursor:pointer"><input type="checkbox" id="'+inpId+'" '+chk+' onchange="markDirty(\''+k+'\')" style="width:auto;margin:0"> '+label+'</label>'}else if(typ==='password'){inp='<label>'+label+'</label><input type="password" id="'+inpId+'" value="'+escHtml(sv)+'" placeholder="'+escHtml(ph)+'" onchange="markDirty(\''+k+'\')">'}else if(typ==='text'){inp='<label>'+label+'</label><textarea id="'+inpId+'" onchange="markDirty(\''+k+'\')">'+escHtml(sv)+'</textarea>'}else if(typ==='select'&&opts.length>0){let sel='<label>'+label+'</label><select id="'+inpId+'" onchange="markDirty(\''+k+'\')">';opts.forEach(o=>{sel+='<option value="'+escHtml(o)+'"'+(sv===o?' selected':'')+'>'+escHtml(o)+'</option>'});sel+='</select>';inp=sel}else if(typ==='int'){inp='<label>'+label+'</label><input type="number" id="'+inpId+'" value="'+escHtml(sv)+'" placeholder="'+escHtml(ph)+'" onchange="markDirty(\''+k+'\')">'}else{inp='<label>'+label+'</label><input id="'+inpId+'" value="'+escHtml(sv)+'" placeholder="'+escHtml(ph)+'" onchange="markDirty(\''+k+'\')">'}html+='<div class="card"><button class="btn btn-primary btn-sm save-btn" onclick="saveSetting(\''+k+'\')" style="float:right;margin-top:-4px">ä¿<EFBFBD>å­˜</button><div class="settings-key">'+escHtml(k)+'</div>'+inp;if(desc){html+='<p style="color:var(--text-muted);font-size:11px;margin-top:-6px">'+escHtml(desc)+'</p>'}html+='</div>'})}if(state.selectedSection==='core'){let srcNames=Object.keys(sourceMap).sort();srcNames.forEach(sn=>{let baseKey='core.llm.sources.'+sn;let srcHtml='<div class="card" style="border-left:3px solid var(--accent)"><h2 style="display:flex;justify-content:space-between;align-items:center"><span>&#127760; '+escHtml(sn)+'</span><button class="btn btn-danger btn-sm" onclick="deleteSource(\''+sn+'\')" style="font-size:10px">删除</button></h2>';let fields=[{key:'adapter',label:'é€é…<C3A9>å™?},{key:'base_url',label:'API 地å<C2B0>€'},{key:'model',label:'模型'},{key:'api_key',label:'API 密钥',typ:'password'},{key:'thinking_enabled',label:'深度æ€<C3A6>è€?,typ:'bool'}];fields.forEach(f=>{let fk=baseKey+'.'+f.key;let fv=state.settings[fk];let fsv=typeof fv==='object'?JSON.stringify(fv):String(fv||'');let fm=state.meta?.[fk];let ftyp=f.typ||fm?.type||'string';let finpId='inp-'+(baseKey+'.'+f.key).replace(/\./g,'_');let finp='';if(ftyp==='bool'){let chk=fsv==='true'?'checked':'';finp='<label style="display:flex;align-items:center;gap:8px;cursor:pointer;margin-bottom:6px"><input type="checkbox" id="'+finpId+'" '+chk+' onchange="markDirty(\''+baseKey+'.'+f.key+'\')" style="width:auto;margin:0"> '+f.label+'</label>'}else if(ftyp==='password'){finp='<label style="font-size:11px;color:var(--text-secondary)">'+f.label+'</label><input type="password" id="'+finpId+'" value="'+escHtml(fsv)+'" placeholder="留空则使用全局密钥" onchange="markDirty(\''+baseKey+'.'+f.key+'\')" style="margin-bottom:6px">'}else if(f.key==='adapter'&&window._adapters&&window._adapters.length){let sel='<label style="font-size:11px;color:var(--text-secondary)">'+f.label+'</label><select id="'+finpId+'" onchange="markDirty(\''+baseKey+'.'+f.key+'\')" style="margin-bottom:6px">';window._adapters.forEach(a=>{sel+='<option value="'+escHtml(a.name)+'" '+(a.name===fsv?'selected':'')+'>'+escHtml(a.name)+'</option>'});sel+='</select>';finp=sel}else{finp='<label style="font-size:11px;color:var(--text-secondary)">'+f.label+'</label><input id="'+finpId+'" value="'+escHtml(fsv)+'" placeholder="输入'+f.label+'" onchange="markDirty(\''+baseKey+'.'+f.key+'\')" style="margin-bottom:6px">'}srcHtml+=finp});srcHtml+='<button class="btn btn-primary btn-sm" onclick="saveSetting(\''+baseKey+'.adapter\');saveSetting(\''+baseKey+'.base_url\');saveSetting(\''+baseKey+'.model\');saveSetting(\''+baseKey+'.api_key\');if(document.getElementById(\''+('inp-'+baseKey+'.thinking_enabled').replace(/\./g,'_')+'\'))saveSetting(\''+baseKey+'.thinking_enabled\');toast(\'æº?\\\''+sn+'\\\' å·²ä¿<C3A4>å­˜\')" style="margin-top:6px">ä¿<EFBFBD>å­˜æº?/button></div>';html+=srcHtml});html+='<div style="margin-top:16px;text-align:center"><button class="btn btn-primary" onclick="showAddSourceDialog()" style="min-width:160px">+ 添加æ–?LLM æº?/button></div>'};if(state.selectedSection==='plugin.mcp'){Object.keys(mcpServerMap).sort().forEach(sn=>{let baseKey='plugin.mcp.servers.'+sn;let cmd=state.settings[baseKey+'.command'],url=state.settings[baseKey+'.url'];if((!cmd||cmd==='<nil>')&&(!url||url==='<nil>'))return;let html2='<div class="card" style="border-left:3px solid var(--accent);margin-top:12px"><h2 style="display:flex;justify-content:space-between;align-items:center"><span>&#9881; '+escHtml(sn)+'</span><button class="btn btn-danger btn-sm" onclick="deleteMCPServer(\''+sn+'\')" style="font-size:10px">删除</button></h2>';let fields=[{key:'command',label:'命令'},{key:'url',label:'URL'},{key:'args',label:'å<>æ•°(JSON)'},{key:'env',label:'环境å<C692>˜é‡<C3A9>(JSON)'}];fields.forEach(f=>{let fk=baseKey+'.'+f.key;let fv=state.settings[fk];let fsv=typeof fv==='object'?JSON.stringify(fv):String(fv||'');let finpId='inp-'+fk.replace(/\./g,'_');let finp='';if(f.key==='args'||f.key==='env'){finp='<label style="font-size:11px;color:var(--text-secondary)">'+f.label+'</label><textarea id="'+finpId+'" onchange="markDirty(\''+fk+'\')" style="margin-bottom:6px">'+escHtml(fsv)+'</textarea>'}else{finp='<label style="font-size:11px;color:var(--text-secondary)">'+f.label+'</label><input id="'+finpId+'" value="'+escHtml(fsv)+'" placeholder="输入'+f.label+'" onchange="markDirty(\''+fk+'\')" style="margin-bottom:6px">'}html2+=finp});html2+='<button class="btn btn-primary btn-sm" onclick="saveSetting(\''+baseKey+'.command\');saveSetting(\''+baseKey+'.url\');saveSetting(\''+baseKey+'.args\');saveSetting(\''+baseKey+'.env\')" style="margin-top:6px">ä¿<EFBFBD>å­˜</button></div>';html+=html2});html+='<div style="margin-top:16px;text-align:center"><button class="btn btn-primary" onclick="addMCPSource()" style="min-width:160px">+ 添加 MCP æœ<C3A6>务å™?/button></div>'}}html+='</div></div>'