feat: add TF reference refresh button to Terraform Agent menu

- Add dropdown menu (⋮) in Terraform toolbar with "Atualizar Referência TF" button
- Remove standalone reference-status API endpoint, keep only refresh-reference
- Button triggers `terraform providers schema -json` regeneration with progress feedback
- Shows line count and update timestamp after successful refresh
- Update README with new line counts
This commit is contained in:
nogueiraguh
2026-03-08 01:05:18 -03:00
parent 19e481275d
commit 805286c05f
3 changed files with 51 additions and 16 deletions

View File

@@ -320,6 +320,12 @@ tbody tr:last-child td{border-bottom:none}
.tf-badge-run{background:var(--bll);color:var(--bl)}
.tf-badge-err{background:var(--rdl);color:var(--rd)}
.tf-badge-dest{background:var(--t4);color:var(--bg)}
.tf-menu{position:absolute;top:100%;right:0;background:var(--bg);border:1px solid var(--bd);border-radius:8px;box-shadow:0 4px 16px rgba(0,0,0,.12);min-width:220px;z-index:50;padding:.3rem 0;margin-top:4px}
.tf-menu-item{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;font-size:.72rem;color:var(--t1);cursor:pointer;transition:background .12s}
.tf-menu-item:hover{background:var(--bg2)}
.tf-menu-item svg{flex-shrink:0;color:var(--t3)}
.tf-menu-sub{font-size:.6rem;color:var(--t3);margin-left:auto;white-space:nowrap}
.tf-menu-item.loading{opacity:.6;pointer-events:none}
.tf-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center;z-index:100}
.tf-modal{background:var(--bg);border-radius:var(--r);padding:1.5rem;max-width:420px;width:90%;box-shadow:0 8px 30px rgba(0,0,0,.25)}
.tf-modal h3{margin:0 0 .5rem;color:var(--rd)}
@@ -346,7 +352,7 @@ const S={user:null,token:null,tab:'chat',msgs:[],sid:null,reports:[],ociCfg:[],g
cisVer:null,cisCheckResult:null,cisUpdating:false,rptHistFilter:'',chatFiles:[],
tfMsgs:[],tfSid:null,tfModel:'',tfOci:'',tfRegion:'',tfCompartment:'',tfPlan:[],tfCode:'',tfPanel:'',
tfWs:null,tfWsList:[],tfPlanOut:'',tfApplyOut:'',tfDestroyOut:'',tfStatus:'draft',tfRunning:false,tfConfirmDest:false,tfMdOpen:false,
tfComps:[],tfCompLoading:false,tfFiles:[],tfBtab:'files',tfEditIdx:-1,tfResources:null,tfResLoading:false};
tfComps:[],tfCompLoading:false,tfFiles:[],tfBtab:'files',tfEditIdx:-1,tfResources:null,tfResLoading:false,tfRefStatus:''};
const API='/api';
async function $api(p,o={}){const h={...(o.headers||{})};if(S.token)h['Authorization']='Bearer '+S.token;
@@ -600,6 +606,32 @@ async function clrChat(){if(S.sid)try{await $api('/chat/'+S.sid,{method:'DELETE'
function newChat(){S.msgs=[];S.sid=null;S.chatFiles=[];R()}
function newTfChat(){S.tfMsgs=[];S.tfSid=null;S.tfPlan=[];S.tfCode='';S.tfFiles=[];S.tfWs=null;S.tfPlanOut='';S.tfApplyOut='';S.tfDestroyOut='';S.tfStatus='draft';S.tfRunning=false;S.tfConfirmDest=false;S.tfEditIdx=-1;R()}
function tfToggleMenu(){
const m=document.getElementById('tfMenu');
if(!m)return;
const show=m.style.display==='none';
m.style.display=show?'block':'none';
if(show){const h=e=>{if(!m.contains(e.target)&&!e.target.closest('[onclick*="tfToggleMenu"]')){m.style.display='none';document.removeEventListener('click',h)}};setTimeout(()=>document.addEventListener('click',h),0)}
}
async function tfRefreshRef(){
const item=document.querySelector('.tf-menu-item');
const sub=document.getElementById('tfRefStatus');
if(item)item.classList.add('loading');
if(sub)sub.textContent='Atualizando...';
try{
const r=await $api('/terraform/refresh-reference',{method:'POST'});
if(r.ok){
S.tfRefStatus=r.lines+' linhas — '+r.updated_at;
if(sub)sub.textContent=S.tfRefStatus;
alert('Referência Terraform atualizada com sucesso!\n'+r.lines+' linhas de recursos OCI.');
}else{
alert('Erro ao atualizar: '+(r.error||'Erro desconhecido'));
if(sub)sub.textContent='Erro';
}
}catch(e){alert('Erro: '+e.message);if(sub)sub.textContent='Erro'}
finally{if(item)item.classList.remove('loading');const m=document.getElementById('tfMenu');if(m)m.style.display='none'}
}
async function loadHistory(type){
try{const h=await $api('/chat/sessions?agent_type='+type+'&limit=50');
if(type==='chat')S.chatHistory=h;else S.tfHistory=h}
@@ -758,6 +790,16 @@ function rTerraform(){
${ociSel}${compSel}
${stBadge}
<div style="flex:1"></div>
<div style="position:relative">
<div class="tf-file-btn" onclick="tfToggleMenu()" title="Menu" style="width:24px;height:24px;cursor:pointer"><svg viewBox="0 0 16 16" width="14" height="14" fill="var(--t3)"><path d="M8 4.5a1.5 1.5 0 110-3 1.5 1.5 0 010 3zm0 5a1.5 1.5 0 110-3 1.5 1.5 0 010 3zm0 5a1.5 1.5 0 110-3 1.5 1.5 0 010 3z"/></svg></div>
<div class="tf-menu" id="tfMenu" style="display:none">
<div class="tf-menu-item" onclick="tfRefreshRef()">
<svg viewBox="0 0 16 16" width="13" height="13" fill="currentColor"><path d="M8 1a7 7 0 106.33 4h-2.1A5 5 0 108 13a5 5 0 004.24-2.36l1.52 1.02A7 7 0 018 1z"/><path d="M11 1v4h4" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>
<span>Atualizar Referência TF</span>
<span class="tf-menu-sub" id="tfRefStatus">${S.tfRefStatus||''}</span>
</div>
</div>
</div>
<div class="tf-file-btn" onclick="newTfChat()" title="Nova conversa" style="width:24px;height:24px"><svg viewBox="0 0 16 16" width="12" height="12" fill="var(--t3)"><path d="M8 2v12M2 8h12" stroke="var(--t3)" stroke-width="2" stroke-linecap="round"/></svg></div>
</div>
<div class="tf-msgs" id="tfchm">${ms}</div>