Update cloudflare.html
This commit is contained in:
@@ -13,6 +13,15 @@
|
||||
<h1 class="text-2xl font-bold">Cloudflare API</h1>
|
||||
<p class="text-xs text-slate-500 mt-0.5">Conexión con tu cuenta de Cloudflare para visualizar zonas, DNS, SSL y reglas de firewall.</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button @click="diagnosModal = true; diagnosToken()"
|
||||
class="flex items-center gap-2 border border-gray-300 text-gray-600 text-sm font-medium px-4 py-2 rounded-lg hover:bg-gray-50"
|
||||
title="Ver permisos reales del token">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126ZM12 15.75h.007v.008H12v-.008Z"/>
|
||||
</svg>
|
||||
Diagnosticar
|
||||
</button>
|
||||
<button @click="configModal = true"
|
||||
class="flex items-center gap-2 text-white text-sm font-medium px-4 py-2 rounded-lg"
|
||||
style="background-color:#8eb02f"
|
||||
@@ -24,6 +33,7 @@
|
||||
</svg>
|
||||
Configurar Token
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alerta sin config -->
|
||||
@@ -202,6 +212,86 @@
|
||||
|
||||
</div><!-- /container -->
|
||||
|
||||
<!-- ─── Modal: Diagnóstico de Token ─── -->
|
||||
<div x-show="diagnosModal" x-cloak class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4"
|
||||
@click.self="diagnosModal=false">
|
||||
<div class="bg-white rounded-xl shadow-xl w-full max-w-2xl max-h-[90vh] flex flex-col">
|
||||
<div class="flex items-center justify-between px-5 py-4 border-b shrink-0">
|
||||
<h3 class="font-semibold text-sm">Diagnóstico del Token</h3>
|
||||
<button @click="diagnosModal=false" class="text-gray-400 hover:text-gray-600">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="p-5 overflow-y-auto flex-1">
|
||||
<!-- Cargando -->
|
||||
<div x-show="diagnosLoading" class="flex items-center gap-2 text-sm text-gray-500">
|
||||
<svg class="animate-spin h-4 w-4" fill="none" viewBox="0 0 24 24">
|
||||
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"/>
|
||||
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8H4z"/>
|
||||
</svg>
|
||||
Consultando Cloudflare API…
|
||||
</div>
|
||||
<!-- Resultado resumen -->
|
||||
<template x-if="diagnosData && !diagnosLoading">
|
||||
<div class="space-y-4">
|
||||
<!-- Hint destacado -->
|
||||
<div :class="diagnosData.hint && diagnosData.hint.startsWith('Token válido') ? 'bg-green-50 border-green-300 text-green-800' : 'bg-amber-50 border-amber-300 text-amber-800'"
|
||||
class="border rounded-lg p-3 text-sm font-medium">
|
||||
<span x-text="diagnosData.hint || diagnosData.error || 'Sin datos'"></span>
|
||||
</div>
|
||||
<!-- Tarjetas de permisos -->
|
||||
<div class="grid grid-cols-2 gap-3" x-show="diagnosData.permissions_test">
|
||||
<div class="border rounded-lg p-3">
|
||||
<p class="text-xs font-medium text-gray-500 mb-1">Zone:Zone:Read</p>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span :class="diagnosData.permissions_test?.zone_read?.ok ? 'bg-green-500' : 'bg-red-500'" class="h-2.5 w-2.5 rounded-full shrink-0"></span>
|
||||
<span class="text-xs" x-text="diagnosData.permissions_test?.zone_read?.ok ? 'OK' : (diagnosData.permissions_test?.zone_read?.error || 'Error')"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border rounded-lg p-3">
|
||||
<p class="text-xs font-medium text-gray-500 mb-1">Zone:DNS:Read</p>
|
||||
<div class="flex items-center gap-1.5">
|
||||
<span :class="diagnosData.permissions_test?.dns_read?.ok ? 'bg-green-500' : 'bg-red-500'" class="h-2.5 w-2.5 rounded-full shrink-0"></span>
|
||||
<span class="text-xs" x-text="diagnosData.permissions_test?.dns_read?.ok ? 'OK' : (diagnosData.permissions_test?.dns_read?.error || 'Error')"></span>
|
||||
</div>
|
||||
<p class="text-xs text-gray-400 mt-1 font-mono truncate" x-show="diagnosData.permissions_test?.dns_read?.zone_tested"
|
||||
x-text="'Zona: ' + diagnosData.permissions_test?.dns_read?.zone_tested"></p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Info del token -->
|
||||
<div class="grid grid-cols-2 gap-2 text-xs text-gray-600">
|
||||
<div><span class="font-medium">Token ID:</span> <span class="font-mono" x-text="diagnosData.token_id || '—'"></span></div>
|
||||
<div><span class="font-medium">Estado:</span> <span x-text="diagnosData.token_status || '—'"></span></div>
|
||||
<div><span class="font-medium">Longitud:</span> <span x-text="diagnosData.token_len + ' chars'"></span></div>
|
||||
<div><span class="font-medium">Tenía chars sucios:</span> <span x-text="diagnosData.was_dirty ? 'SÍ (saneado)' : 'No'"></span></div>
|
||||
</div>
|
||||
<!-- Políticas raw -->
|
||||
<div x-show="diagnosData.policies">
|
||||
<p class="text-xs font-medium text-gray-500 mb-1">Políticas registradas en Cloudflare:</p>
|
||||
<pre class="bg-gray-50 border rounded p-3 text-xs overflow-x-auto whitespace-pre-wrap break-all"
|
||||
x-text="JSON.stringify(diagnosData.policies, null, 2)"></pre>
|
||||
</div>
|
||||
<!-- JSON completo -->
|
||||
<details class="text-xs">
|
||||
<summary class="cursor-pointer text-gray-400 hover:text-gray-600">Ver JSON completo</summary>
|
||||
<pre class="mt-2 bg-gray-50 border rounded p-3 overflow-x-auto whitespace-pre-wrap break-all"
|
||||
x-text="JSON.stringify(diagnosData, null, 2)"></pre>
|
||||
</details>
|
||||
</div>
|
||||
</template>
|
||||
<!-- Error de conexión -->
|
||||
<div x-show="diagnosError && !diagnosLoading" class="bg-red-50 border border-red-200 rounded-lg p-3 text-sm text-red-700" x-text="diagnosError"></div>
|
||||
</div>
|
||||
<div class="px-5 py-3 border-t shrink-0 flex justify-between items-center">
|
||||
<button @click="diagnosToken()" :disabled="diagnosLoading"
|
||||
class="px-4 py-2 border rounded text-sm hover:bg-gray-50 disabled:opacity-40">Reintentar</button>
|
||||
<button @click="diagnosModal=false" class="px-4 py-2 text-white text-sm rounded" style="background-color:#8eb02f">Cerrar</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ─── Modal: Configurar Token ─── -->
|
||||
<div x-show="configModal" x-cloak class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 px-4"
|
||||
@click.self="configModal=false">
|
||||
@@ -267,6 +357,10 @@ document.addEventListener('alpine:init', () => {
|
||||
fwRules: [],
|
||||
selectedZoneId: '',
|
||||
configModal: false,
|
||||
diagnosModal: false,
|
||||
diagnosLoading: false,
|
||||
diagnosData: null,
|
||||
diagnosError: '',
|
||||
cfgForm: { id: 0, api_token: '', account_id: '', nota: '' },
|
||||
toast: { show: false, msg: '', type: 'ok' },
|
||||
|
||||
@@ -336,7 +430,7 @@ document.addEventListener('alpine:init', () => {
|
||||
this.loading = true;
|
||||
try {
|
||||
const res = await axios.get('/app/cloudflare/verify');
|
||||
const status = res.data?.data?.status || 'active';
|
||||
const status = res.data?.data?.status || res.data?.token_status || 'active';
|
||||
this.showToast('Token válido — estado: ' + status);
|
||||
} catch (e) {
|
||||
this.showToast(e.response?.data?.error || 'Token inválido o sin permisos', 'error');
|
||||
@@ -344,6 +438,20 @@ document.addEventListener('alpine:init', () => {
|
||||
this.loading = false;
|
||||
},
|
||||
|
||||
async diagnosToken() {
|
||||
this.diagnosLoading = true;
|
||||
this.diagnosData = null;
|
||||
this.diagnosError = '';
|
||||
try {
|
||||
const res = await axios.get('/app/cloudflare/verify');
|
||||
this.diagnosData = res.data;
|
||||
} catch (e) {
|
||||
this.diagnosError = e.response?.data?.error || e.message || 'Error al consultar';
|
||||
this.diagnosData = e.response?.data || null;
|
||||
}
|
||||
this.diagnosLoading = false;
|
||||
},
|
||||
|
||||
showToast(msg, type = 'ok') {
|
||||
this.toast = { show: true, msg, type };
|
||||
setTimeout(() => this.toast.show = false, 3500);
|
||||
|
||||
Reference in New Issue
Block a user