feat: export/import configuration and multiple bug fixes
- Add export/import endpoints for full config backup (OCI, GenAI, MCP, prompts, settings, ADB) - Export includes private keys (base64) for complete environment migration - Import merges by ID (skips existing, no duplicates) - Fix Resource Plan parser to recognize free-form format (model skips ```plan blocks) - Fix replan not clearing previous apply/destroy outputs - Fix duplicate CIS Compliance Scanner MCP server on multi-worker startup - Add Terraform prompt editor with auto-save in menu
This commit is contained in:
@@ -1824,7 +1824,15 @@ ${ddItems||'<div style="padding:.5rem;color:var(--t4);font-size:.72rem">Nenhuma
|
||||
</div>`:''}</div>`}
|
||||
function ociFormPickReg(r){S.ociFormRegVal=r;S.ociFormRegOpen=false;S.ociFormRegFilter='';R()}
|
||||
function rOci(){const eo=S.editing?.type==='oci'?S.ociCfg.find(c=>c.id===S.editing.id):null;
|
||||
return`<div class="cd"><div class="ct">☁️ Credenciais Registradas</div><div id="ocm"></div>
|
||||
return`<div class="cd" style="display:flex;align-items:center;justify-content:space-between;padding:.6rem 1rem">
|
||||
<div style="font-size:.78rem;font-weight:600;color:var(--t2)">⚙️ Configuração do Sistema</div>
|
||||
<div style="display:flex;gap:.4rem;align-items:center">
|
||||
<button class="btn bp bsm" onclick="cfgExport()">📤 Exportar</button>
|
||||
<button class="btn bs bsm" onclick="document.getElementById('cfgImportFile').click()">📥 Importar</button>
|
||||
<input type="file" id="cfgImportFile" accept=".json" style="display:none" onchange="cfgImport(this)">
|
||||
</div></div>
|
||||
<div id="cfgMsg"></div>
|
||||
<div class="cd"><div class="ct">☁️ Credenciais Registradas</div><div id="ocm"></div>
|
||||
<table><thead><tr><th>Tenancy</th><th>Region</th><th>Detalhes</th><th>Ações</th></tr></thead><tbody>
|
||||
${S.ociCfg.map(c=>`<tr${eo&&eo.id===c.id?' style="background:var(--bg3)"':''}><td><strong>${c.tenancy_name}</strong><br><span style="font-size:.66rem;color:var(--t4)">${c.created_at}</span></td><td><span class="tag">${c.region}</span></td>
|
||||
<td style="font-family:var(--fm);font-size:.66rem;color:var(--t4);line-height:1.6"><span title="Fingerprint">🔑 ••••••••••••••••••••</span><br><span title="Tenancy OCID">🏢 ${c.tenancy_ocid}</span><br><span title="User OCID">👤 ${c.user_ocid}</span><br><span title="Compartment">📦 ${c.compartment_id||'—'}</span></td>
|
||||
@@ -1862,6 +1870,39 @@ async function sOci(){const tn=document.getElementById('otn').value;
|
||||
const btn=document.getElementById('obtn');btn.disabled=true;btn.textContent='Salvando...';sm('om','<span class="spinner" style="display:inline-block;width:14px;height:14px;vertical-align:middle"></span> Salvando credencial...','i');
|
||||
try{const url=isEdit?'/oci/configs/'+S.editing.id:'/oci/config';const method=isEdit?'PUT':'POST';
|
||||
await $api(url,{method,body:fd,headers:{}});S.editing=null;S.ociFormRegVal='';S.ociFormRegFilter='';S.ociCfg=await $api('/oci/configs');sm('om','✅ Credencial '+(isEdit?'atualizada':'salva')+' com sucesso!','s');R()}catch(e){sm('om',e.message,'e');btn.disabled=false;btn.textContent=isEdit?'Salvar Alterações':'Salvar Credencial'}}
|
||||
async function cfgExport(){
|
||||
try{
|
||||
const resp=await fetch(API+'/config/export',{headers:S.token?{'Authorization':'Bearer '+S.token}:{}});
|
||||
if(!resp.ok)throw new Error('Erro ao exportar');
|
||||
const blob=await resp.blob();
|
||||
const url=URL.createObjectURL(blob);
|
||||
const a=document.createElement('a');a.href=url;
|
||||
a.download=resp.headers.get('content-disposition')?.match(/filename="(.+)"/)?.[1]||'config-export.json';
|
||||
a.click();URL.revokeObjectURL(url);
|
||||
sm('cfgMsg','✅ Configuração exportada com sucesso!','s');
|
||||
}catch(e){sm('cfgMsg','❌ '+e.message,'e')}
|
||||
}
|
||||
async function cfgImport(input){
|
||||
const file=input.files[0];if(!file)return;
|
||||
try{
|
||||
const fd=new FormData();fd.append('file',file);
|
||||
const resp=await fetch(API+'/config/import',{method:'POST',headers:S.token?{'Authorization':'Bearer '+S.token}:{},body:fd});
|
||||
if(!resp.ok){const err=await resp.json();throw new Error(err.detail||'Erro ao importar')}
|
||||
const d=await resp.json();
|
||||
const parts=[];
|
||||
if(d.oci_configs)parts.push(d.oci_configs+' OCI configs');
|
||||
if(d.genai_configs)parts.push(d.genai_configs+' GenAI configs');
|
||||
if(d.mcp_servers)parts.push(d.mcp_servers+' MCP servers');
|
||||
if(d.system_prompts)parts.push(d.system_prompts+' prompts');
|
||||
if(d.app_settings)parts.push(d.app_settings+' settings');
|
||||
if(d.adb_vector_configs)parts.push(d.adb_vector_configs+' ADB configs');
|
||||
if(d.skipped)parts.push(d.skipped+' ignorados (já existem)');
|
||||
sm('cfgMsg','✅ Importado: '+parts.join(', '),'s');
|
||||
[S.ociCfg,S.genaiCfg,S.mcpSvr]=await Promise.all([$api('/oci/configs'),$api('/genai/configs'),$api('/mcp/servers')]);
|
||||
R();
|
||||
}catch(e){sm('cfgMsg','❌ '+e.message,'e')}
|
||||
finally{input.value=''}
|
||||
}
|
||||
async function tOci(id){try{const d=await $api('/oci/test/'+id,{method:'POST'});sm('ocm',d.status==='success'?'✅ Conexão OK!':'❌ '+d.message,d.status==='success'?'s':'e');refreshCLogs('oci')}catch(e){sm('ocm',e.message,'e')}}
|
||||
async function dOci(id){if(!confirm('Excluir credencial?'))return;await $api('/oci/configs/'+id,{method:'DELETE'});S.ociCfg=await $api('/oci/configs');R()}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user