/** * Domínios VM112 — Account Home card + modal (Spec 017) */ const DeskVm112Domains = (() => { const API_BASE = '/api'; let _domains = []; let _query = ''; function canManage() { return typeof canRunAudit === 'function' && canRunAudit(); } function isEnabled() { return window.DeskModules?.isEnabled('vm112-domains') !== false; } function esc(s) { return String(s ?? '') .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function filtered() { const q = _query.trim().toLowerCase(); if (!q) return _domains; return _domains.filter((d) => { const blob = [ d.domain, d.portal_admin_email, (d.accounts_preview || []).join(' '), (d.portal_users || []).map((u) => u.login_id).join(' '), ].join(' ').toLowerCase(); return blob.includes(q); }); } function statusBadges(d) { const parts = []; parts.push(d.carbonio_exists ? 'Carbonio' : 'sem CD'); parts.push(d.site_folder_exists ? 'site' : 'sem pasta'); parts.push(`${d.account_count != null ? d.account_count : (d.carbonio_exists ? 'CD' : '0')} contas`); return parts.join(' '); } function cardHtml() { if (!canManage() || !isEnabled()) return ''; const rows = filtered() .map((d) => ` `) .join(''); return `

Domínios orquestrados (VM112)

${rows || '

Nenhum domínio encontrado na VM112.

'}

${filtered().length} / ${_domains.length} domínio(s) · Admin only

`; } async function loadDomains() { const res = await fetchWithTimeout(`${API_BASE}/v1/vm112/domains`, { headers: authHeaders({ 'Content-Type': 'application/json' }), }, 120000); if (res.status === 401) { logout(); throw new Error('sessão expirada'); } if (!res.ok) { const data = await res.json().catch(() => ({})); throw new Error(data.detail || `${res.status} /v1/vm112/domains`); } const data = await res.json(); _domains = data.domains || []; return _domains; } function bindCard(root) { if (!root) return; root.querySelector('#vm112-domains-search')?.addEventListener('input', (e) => { _query = e.target.value; const list = root.querySelector('#vm112-domains-list'); const panel = root.querySelector('#vm112-domains-panel'); if (list && panel) { const foot = panel.querySelector('.vm112-domains-foot'); const html = filtered().map((d) => ` `).join(''); list.innerHTML = html || '

Nenhum resultado.

'; if (foot) foot.textContent = `${filtered().length} / ${_domains.length} domínio(s) · Admin only`; list.querySelectorAll('[data-vm112-domain]').forEach((btn) => { btn.addEventListener('click', () => openModal(btn.dataset.vm112Domain)); }); } }); root.querySelector('#vm112-domains-refresh')?.addEventListener('click', async () => { const list = root.querySelector('#vm112-domains-list'); if (list) list.innerHTML = '

A carregar VM112…

'; try { await loadDomains(); await injectCard(root.closest('.cf-home') || root); } catch (e) { if (list) list.innerHTML = `

Erro: ${esc(e.message)}

`; } }); root.querySelectorAll('[data-vm112-domain]').forEach((btn) => { btn.addEventListener('click', () => openModal(btn.dataset.vm112Domain)); }); } async function injectCard(cfHome) { if (!cfHome || !canManage() || !isEnabled()) return; const existing = cfHome.querySelector('#vm112-domains-panel'); if (existing) existing.remove(); const grid = cfHome.querySelector('.cf-grid-2'); const loading = document.createElement('div'); loading.id = 'vm112-domains-panel'; loading.className = 'cf-panel vm112-domains-panel'; loading.innerHTML = '

Domínios orquestrados (VM112)

A carregar lista VM112 (pode demorar ~1 min)…

'; if (grid) grid.before(loading); try { if (!_domains.length) await loadDomains(); } catch (e) { loading.innerHTML = `

Domínios orquestrados (VM112)

Erro: ${esc(e.message)}

`; return; } loading.remove(); const wrap = document.createElement('div'); wrap.innerHTML = cardHtml(); const card = wrap.firstElementChild; const grid = cfHome.querySelector('.cf-grid-2'); if (grid) grid.before(card); else cfHome.appendChild(card); bindCard(card); } function closeModal() { const modal = document.getElementById('vm112-domain-modal'); if (!modal) return; modal.classList.add('hidden'); modal.setAttribute('aria-hidden', 'true'); } function openModal(domain) { const modal = document.getElementById('vm112-domain-modal'); const body = document.getElementById('vm112-domain-modal-body'); const title = document.getElementById('vm112-domain-modal-title'); const sub = document.getElementById('vm112-domain-modal-sub'); if (!modal || !body) return; modal.classList.remove('hidden'); modal.setAttribute('aria-hidden', 'false'); title.textContent = domain; sub.textContent = 'A carregar detalhe VM112…'; body.innerHTML = '

A carregar…

'; loadModal(domain); modal.querySelector('[data-close-vm112-modal]')?.addEventListener('click', closeModal, { once: true }); modal.querySelector('.modal-backdrop')?.addEventListener('click', closeModal, { once: true }); } async function loadModal(domain) { const body = document.getElementById('vm112-domain-modal-body'); const sub = document.getElementById('vm112-domain-modal-sub'); try { const d = await fetchWithTimeout(`${API_BASE}/v1/vm112/domains/${encodeURIComponent(domain)}`, { headers: authHeaders({ 'Content-Type': 'application/json' }), }, 120000).then(async (res) => { if (!res.ok) { const data = await res.json().catch(() => ({})); throw new Error(data.detail || `${res.status}`); } return res.json(); }); sub.textContent = `${d.account_count || 0} conta(s) · ${d.mail_host || ''}`; const steps = (d.infra_status?.steps || []) .map((s) => `
  • ${esc(s.label)} — ${esc(s.message)}
  • `) .join(''); const accounts = (d.accounts || d.accounts_preview || []) .map((a) => `
  • ${esc(a)}
  • `).join('') || '
  • Nenhuma
  • '; const cf = d.cloudflare_zone; const cfTxt = cf?.name ? `Zona ${cf.name} (${cf.status || '—'})` : (cf?.error ? `Erro CF: ${cf.error}` : 'Sem zona na conta Ibytera'); body.innerHTML = ` `; body.querySelector('#vm112-purge-btn')?.addEventListener('click', () => runPurge(domain)); } catch (e) { body.innerHTML = `

    Erro: ${esc(e.message)}

    `; } } async function runPurge(domain) { const msg = document.getElementById('vm112-purge-msg'); const confirmDomain = document.getElementById('vm112-purge-confirm')?.value?.trim() || ''; const rootPassword = document.getElementById('vm112-purge-root-pwd')?.value || ''; if (!confirmDomain || !rootPassword) { if (msg) msg.textContent = 'Preencha confirmação do domínio e senha Root.'; return; } if (!window.confirm(`PURGE definitivo de ${domain}? Esta ação não pode ser desfeita.`)) return; const btn = document.getElementById('vm112-purge-btn'); if (btn) { btn.disabled = true; btn.textContent = 'A apagar…'; } if (msg) msg.textContent = 'A executar purge VM112 + Desk…'; try { const res = await api(`/v1/vm112/domains/${encodeURIComponent(domain)}/purge`, { method: 'POST', body: JSON.stringify({ confirm_domain: confirmDomain, root_password: rootPassword }), }); if (msg) msg.textContent = `Concluído. Desk: ${JSON.stringify(res.desk || {})}`; _domains = _domains.filter((d) => d.domain !== domain); setTimeout(() => { closeModal(); const panel = document.getElementById('vm112-domains-panel'); if (panel) document.getElementById('vm112-domains-refresh')?.click(); }, 1500); } catch (e) { if (msg) msg.textContent = e.message || 'Purge falhou'; if (btn) { btn.disabled = false; btn.textContent = 'Apagar domínio e todos os dados'; } } } return { injectCard, loadDomains, openModal, canManage, isEnabled }; })(); window.DeskVm112Domains = DeskVm112Domains;