185 lines
9.0 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

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.

{
"widgettype": "VBox",
"options": {
"width": "100%",
"height": "100%",
"padding": "24px",
"gap": "16px"
},
"subwidgets": [
{
"widgettype": "Html",
"options": {
"html": "<script>setTimeout(function(){fetch('/pipeline-sdlc/api/work_env.dspy?action=get&owner_type=org').then(function(r){return r.json()}).then(function(d){if(d.ok&&d.env){var f=bricks.getWidgetById('remote_form',bricks.app);if(f){var env=d.env||{};for(var k in env){if(f.name_inputs&&f.name_inputs[k]){f.name_inputs[k].setValue(env[k]);}}}}})},300);</script>",
"height": "0",
"width": "0"
}
},
{
"widgettype": "Title3",
"options": {
"otext": "机构远程空间配置", "text": "机构远程空间配置", "i18n": true
}
},
{
"widgettype": "Text",
"options": {
"otext": "设置机构的远程工作空间。远程模式下,机构所有用户的工作目录与沙箱命令都在远程主机执行(远程主机需部署 bwrap。", "text": "设置机构的远程工作空间。远程模式下,机构所有用户的工作目录与沙箱命令都在远程主机执行(远程主机需部署 bwrap。", "i18n": true,
"cfontsize": 0.9,
"color": "#64748b"
}
},
{
"widgettype": "VBox",
"options": {
"bgcolor": "#fff",
"border": "1px solid #e2e8f0",
"borderRadius": "12px",
"padding": "20px",
"gap": "12px"
},
"subwidgets": [
{
"widgettype": "Form",
"id": "remote_form",
"options": {
"name": "remote_form",
"cols": 2,
"fields": [
{
"name": "mode",
"uitype": "code",
"label": "工作模式",
"cwidth": 12,
"data": [
{
"value": "local",
"text": "本地bwrap 沙箱)"
},
{
"value": "remote",
"text": "远程SSH + bwrap 沙箱)"
}
],
"valueField": "value",
"textField": "text"
},
{
"name": "remote_host",
"uitype": "str",
"label": "远程主机",
"cwidth": 24,
"placeholder": "例如 192.168.1.10 或 remote.example.com"
},
{
"name": "remote_port",
"uitype": "str",
"label": "远程端口",
"cwidth": 8,
"value": "22"
},
{
"name": "remote_user",
"uitype": "str",
"label": "远程用户",
"cwidth": 12
},
{
"name": "remote_dir",
"uitype": "str",
"label": "远程目录",
"cwidth": 24,
"placeholder": "相对路径,从远程用户 home 目录开始,例如 work/pipeline"
}
]
}
},
{
"widgettype": "HBox",
"options": {
"gap": "12px"
},
"subwidgets": [
{
"widgettype": "Button",
"id": "save_btn",
"options": {
"label": "保存配置"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var f=bricks.getWidgetById('remote_form',bricks.app);var v=f?f._getValue():{};var body=new URLSearchParams();body.append('action','set');body.append('owner_type','org');body.append('mode',v.mode||'local');body.append('remote_host',v.remote_host||'');body.append('remote_port',v.remote_port||'22');body.append('remote_user',v.remote_user||'');body.append('remote_dir',v.remote_dir||'');fetch('/pipeline-sdlc/api/work_env.dspy',{method:'POST',body:body}).then(function(r){return r.json()}).then(function(d){if(d.ok){bricks.show_message({title:'成功',message:'远程空间配置已保存'});}else{bricks.show_error({title:'失败',message:d.error||'未知错误'});}});"
}
]
},
{
"widgettype": "Button",
"id": "test_btn",
"options": {
"label": "测试远程连接"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var f=bricks.getWidgetById('remote_form',bricks.app);var v=f?f._getValue():{};var body=new URLSearchParams();body.append('action','ensure_remote_bwrap');body.append('remote_host',v.remote_host||'');body.append('remote_port',v.remote_port||'22');body.append('remote_user',v.remote_user||'');fetch('/pipeline-sdlc/api/work_env.dspy',{method:'POST',body:body}).then(function(r){return r.json()}).then(function(d){if(d.ok){bricks.show_message({title:'连接成功',message:'远程 bwrap 位置: '+(d.location||'unknown')});}else{bricks.show_error({title:'连接失败',message:d.error||'未知错误'});}});"
}
]
},
{
"widgettype": "Button",
"id": "pubkey_btn",
"options": {
"label": "获取机构公钥"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "fetch('/pipeline-sdlc/api/work_env.dspy?action=get_org_pubkey').then(function(r){return r.json()}).then(function(d){if(d.ok){var t=bricks.getWidgetById('pubkey_text',bricks.app);if(t)t.set_text('机构公钥(复制到远程主机 ~/.ssh/authorized_keys\\\\n'+d.pubkey);}else{bricks.show_error({title:'失败',message:d.error||'未知错误'});}});"
}
]
},
{
"widgettype": "Button",
"id": "init_btn",
"options": {
"label": "初始化远程环境",
"bgcolor": "#0ea5e9",
"color": "#fff"
},
"binds": [
{
"wid": "self",
"event": "click",
"actiontype": "script",
"target": "self",
"script": "var f=bricks.getWidgetById('remote_form',bricks.app);var v=f?f._getValue():{};if(!v.remote_host||!v.remote_dir){bricks.show_error({title:'缺少配置',message:'请先填写远程主机与远程目录并保存'});return;}var btn=this;btn.disabled=true;var body=new URLSearchParams();body.append('action','init_remote_env');body.append('remote_host',v.remote_host);body.append('remote_port',v.remote_port||'22');body.append('remote_user',v.remote_user||'');body.append('remote_dir',v.remote_dir);fetch('/pipeline-sdlc/api/work_env.dspy',{method:'POST',body:body}).then(function(r){return r.json()}).then(function(d){if(!d.ok){btn.disabled=false;bricks.show_error({title:'初始化失败',message:d.error||'未知错误'});return;}var st=d.steps||{};var sk=st.skills||{};var dp=st.deps_found||{};var dl=st.deps_launch||{};var msg='bwrap: '+((st.bwrap&&st.bwrap.ok)?'✓':'✓')+'<br>技能同步: '+(sk.synced?sk.synced.join(', '):'✗')+'<br>待装依赖: '+(dp.specs?dp.specs.length:0)+' 个包(重量级已跳过 '+(dp.heavy_skipped?dp.heavy_skipped.length:0)+' 个)<br>依赖安装进行中…';bricks.show_message({title:'远程环境初始化',message:msg});var tries=0;function poll(){if(tries++>60){btn.disabled=false;bricks.show_error({title:'依赖安装超时',message:'超过10分钟未返回结果请稍后重新点击初始化查询'});return;}fetch('/pipeline-sdlc/api/work_env.dspy?action=init_remote_env_status&owner_type=org').then(function(r){return r.json()}).then(function(s){if(s.status==='running'){setTimeout(poll,10000);return;}btn.disabled=false;if(s.ok){bricks.show_message({title:'远程环境初始化完成',message:'依赖安装成功: '+(s.installed?s.installed.length:0)+' 个包<br>venv: '+(s.venv||'')});}else{bricks.show_error({title:'依赖安装失败',message:(s.error||'')+'<br>失败包: '+((s.failed||[]).join('; ')||'无')+((s.tail)?'<br>日志末尾:<br>'+s.tail.slice(-300):'')});}}).catch(function(e){btn.disabled=false;bricks.show_error({title:'查询失败',message:String(e)});});}setTimeout(poll,8000);}).catch(function(e){btn.disabled=false;bricks.show_error({title:'请求失败',message:String(e)});});"
}
]
}
]
},
{
"widgettype": "Text",
"id": "pubkey_text",
"options": {
"text": "",
"whiteSpace": "pre-wrap",
"cfontsize": 0.85,
"color": "var(--ink-2)"
}
}
]
}
]
}