feat(infra): add pihole rule to infra scope

This commit is contained in:
Nabil Derouiche
2026-06-25 22:15:46 +01:00
parent be63b30285
commit 314f8603aa
32 changed files with 507 additions and 589 deletions
+57 -38
View File
@@ -4,17 +4,36 @@
<style>
/* Hugging Face Inspired Styles */
.hf-card {
background-color: #1f2937; /* Tailwind gray-800 */
border: 1px solid #374151; /* Tailwind gray-700 */
border-radius: 0.75rem;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
border-radius: 1rem;
overflow: hidden;
transition: transform 0.2s, box-shadow 0.2s;
transition: all 0.35s cubic-bezier(0.4,0,0.2,1);
transform-style: preserve-3d;
position: relative;
}
.hf-card:hover {
transform: translateY(-2px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
.dark .hf-card {
background: rgba(15,22,46,0.72);
backdrop-filter: blur(20px) saturate(180%);
-webkit-backdrop-filter: blur(20px) saturate(180%);
border: 1px solid rgba(255,255,255,0.07);
box-shadow: 0 8px 32px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.05);
}
html:not(.dark) .hf-card {
background: #ffffff;
border: 1px solid #e2e8f0;
box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.04);
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
.hf-card::after {
content: '';
position: absolute; inset: 0; border-radius: inherit;
background: linear-gradient(135deg, rgba(255,255,255,0.04) 0%, transparent 60%);
pointer-events: none; z-index: 0;
}
.hf-card > * { position: relative; z-index: 1; }
.hf-card:hover { transform: translateY(-5px) perspective(800px) rotateX(1.5deg) rotateY(-0.5deg); }
.dark .hf-card:hover { box-shadow: 0 24px 64px rgba(0,0,0,0.5), 0 0 0 1px rgba(212,160,26,0.2); }
html:not(.dark) .hf-card:hover { box-shadow: 0 24px 64px rgba(99,102,241,0.15), 0 0 0 1px rgba(212,160,26,0.3); }
.hf-header {
padding: 1rem 1.5rem;
font-weight: 700;
@@ -61,11 +80,11 @@
<div class="flex justify-between items-end mb-2">
<label class="text-sm font-bold text-gray-300 uppercase tracking-wide">Abonnés YouTube</label>
<div class="flex items-center gap-2">
<input type="number" id="yt-subs" class="bg-gray-900 text-white text-sm font-mono rounded border border-gray-600 px-2 py-1 w-24 text-right focus:outline-none focus:border-red-500 transition-colors" value="0">
<span class="text-gray-500 font-mono text-sm">/ 1000</span>
<input type="number" id="yt-subs" class="dark:bg-gray-900 bg-gray-50 text-white text-sm font-mono rounded border border-gray-600 px-2 py-1 w-24 text-right focus:outline-none focus:border-red-500 transition-colors" value="0">
<span class="dark:text-gray-500 text-gray-400 font-mono text-sm">/ 1000</span>
</div>
</div>
<div class="w-full bg-gray-900 rounded-full h-4 overflow-hidden border border-gray-700">
<div class="w-full dark:bg-gray-900 bg-gray-50 rounded-full h-4 overflow-hidden border border-gray-700">
<div id="yt-bar" class="h-full bg-red-500 transition-all duration-700 ease-out" style="width: 0%"></div>
</div>
</div>
@@ -73,11 +92,11 @@
<div class="flex justify-between items-end mb-2">
<label class="text-sm font-bold text-gray-300 uppercase tracking-wide">Revenus Mensuels (€)</label>
<div class="flex items-center gap-2">
<input type="number" id="rev" class="bg-gray-900 text-white text-sm font-mono rounded border border-gray-600 px-2 py-1 w-24 text-right focus:outline-none focus:border-red-500 transition-colors" value="0">
<span class="text-gray-500 font-mono text-sm">/ 300</span>
<input type="number" id="rev" class="dark:bg-gray-900 bg-gray-50 text-white text-sm font-mono rounded border border-gray-600 px-2 py-1 w-24 text-right focus:outline-none focus:border-red-500 transition-colors" value="0">
<span class="dark:text-gray-500 text-gray-400 font-mono text-sm">/ 300</span>
</div>
</div>
<div class="w-full bg-gray-900 rounded-full h-4 overflow-hidden border border-gray-700">
<div class="w-full dark:bg-gray-900 bg-gray-50 rounded-full h-4 overflow-hidden border border-gray-700">
<div id="rev-bar" class="h-full bg-red-500 transition-all duration-700 ease-out" style="width: 0%"></div>
</div>
</div>
@@ -89,7 +108,7 @@
<div class="w-full overflow-x-auto hide-scrollbar pb-2">
<div class="flex space-x-4 min-w-max" id="agents-container">
<!-- Rendered by JS -->
<div class="text-gray-500 italic text-sm p-4">Chargement des agents...</div>
<div class="dark:text-gray-500 text-gray-400 italic text-sm p-4">Chargement des agents...</div>
</div>
</div>
@@ -99,13 +118,13 @@
<!-- 3. REGISTRE PORTS -->
<div class="hf-card">
<div class="hf-header bg-gray-800 text-gray-200 border-b border-gray-700">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path></svg>
<svg class="w-5 h-5 dark:text-gray-400 dark:text-gray-500 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path></svg>
Registre Ports
</div>
<div class="p-6 bg-gray-900">
<div class="p-6 dark:bg-gray-900 bg-gray-50">
<div id="ports-grid" class="flex flex-wrap gap-2">
<!-- Rendered by JS -->
<div class="text-gray-500 italic text-sm">Chargement des ports...</div>
<div class="dark:text-gray-500 text-gray-400 italic text-sm">Chargement des ports...</div>
</div>
</div>
</div>
@@ -113,12 +132,12 @@
<!-- 5. RÈGLES INFRA -->
<div class="hf-card">
<div class="hf-header bg-gray-800 text-gray-200 border-b border-gray-700">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path></svg>
<svg class="w-5 h-5 dark:text-gray-400 dark:text-gray-500 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4"></path></svg>
Règles Infra
</div>
<div class="divide-y divide-gray-700/50 bg-gray-900" id="infra-accordion">
<div class="divide-y divide-gray-700/50 dark:bg-gray-900 bg-gray-50" id="infra-accordion">
<!-- Rendered by JS -->
<div class="p-4 text-gray-500 italic text-sm">Chargement de l'infrastructure...</div>
<div class="p-4 dark:text-gray-500 text-gray-400 italic text-sm">Chargement de l'infrastructure...</div>
</div>
</div>
</div>
@@ -128,10 +147,10 @@
<!-- 7. RACCOURCIS ADMIN -->
<div class="hf-card">
<div class="hf-header bg-gray-800 text-gray-200 border-b border-gray-700">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
<svg class="w-5 h-5 dark:text-gray-400 dark:text-gray-500 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path></svg>
Raccourcis Admin
</div>
<div class="p-4 bg-gray-900 grid grid-cols-2 gap-3">
<div class="p-4 dark:bg-gray-900 bg-gray-50 grid grid-cols-2 gap-3">
<a href="/editor/infra" class="bg-gray-800 hover:bg-gray-700 border border-gray-700 text-gray-200 text-xs font-bold uppercase tracking-wider py-3 px-2 rounded-lg text-center transition">Éditeur Infra</a>
<a href="/keys" class="bg-gray-800 hover:bg-gray-700 border border-gray-700 text-gray-200 text-xs font-bold uppercase tracking-wider py-3 px-2 rounded-lg text-center transition">Gestion Clés</a>
<a href="/audit" class="bg-gray-800 hover:bg-gray-700 border border-gray-700 text-gray-200 text-xs font-bold uppercase tracking-wider py-3 px-2 rounded-lg text-center transition">Logs Complets</a>
@@ -145,7 +164,7 @@
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path></svg>
Stack LLM
</div>
<div class="p-5 space-y-4 bg-gray-900" id="llm-stack">
<div class="p-5 space-y-4 dark:bg-gray-900 bg-gray-50" id="llm-stack">
<div class="animate-pulse space-y-3">
<div class="h-4 bg-gray-800 rounded w-3/4"></div>
<div class="h-4 bg-gray-800 rounded w-1/2"></div>
@@ -156,10 +175,10 @@
<!-- 6. AUDIT RÉCENT -->
<div class="hf-card">
<div class="hf-header bg-gray-800 text-gray-200 border-b border-gray-700">
<svg class="w-5 h-5 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
<svg class="w-5 h-5 dark:text-gray-400 dark:text-gray-500 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
Audit Récent
</div>
<div class="p-5 bg-gray-900">
<div class="p-5 dark:bg-gray-900 bg-gray-50">
<div class="relative border-l-2 border-gray-800 ml-3 space-y-6" id="audit-timeline">
<!-- Rendered by JS -->
</div>
@@ -303,7 +322,7 @@
const tagsHtml = ag.scopes.map(s => `<span class="hf-tag ${style.tag}">${s}</span>`).join('');
html += `
<div class="hf-card w-72 flex-shrink-0 ${style.border} bg-gray-900">
<div class="hf-card w-72 flex-shrink-0 ${style.border} dark:bg-gray-900 bg-gray-50">
<div class="hf-header ${style.bg} ${style.text} border-b ${style.border} flex justify-between">
<span class="tracking-widest">${ag.name}</span>
<span class="w-2.5 h-2.5 rounded-full ${statusColor}"></span>
@@ -313,7 +332,7 @@
${tagsHtml}
</div>
<div class="flex justify-between items-center border-t border-gray-800 pt-3">
<span class="text-xs font-bold text-gray-500 uppercase tracking-widest">Activité</span>
<span class="text-xs font-bold dark:text-gray-500 text-gray-400 uppercase tracking-widest">Activité</span>
<span class="text-xs font-mono text-gray-300">${lastTime}</span>
</div>
</div>
@@ -349,7 +368,7 @@
} else {
// Free - Gray Chip
html += `
<div class="hf-tag bg-gray-800 text-gray-500 border border-gray-700 font-mono text-xs">
<div class="hf-tag bg-gray-800 dark:text-gray-500 text-gray-400 border border-gray-700 font-mono text-xs">
${port}
</div>`;
}
@@ -360,7 +379,7 @@
function renderLLM(data) {
const container = document.getElementById('llm-stack');
if (!data || Object.keys(data).length === 0) {
container.innerHTML = '<div class="text-gray-500 italic text-sm">Données indisponibles</div>';
container.innerHTML = '<div class="dark:text-gray-500 text-gray-400 italic text-sm">Données indisponibles</div>';
return;
}
@@ -387,7 +406,7 @@
function renderInfra(data) {
const container = document.getElementById('infra-accordion');
if (!data || Object.keys(data).length === 0) {
container.innerHTML = '<div class="p-4 text-gray-500 italic text-sm">Aucune règle définie</div>';
container.innerHTML = '<div class="p-4 dark:text-gray-500 text-gray-400 italic text-sm">Aucune règle définie</div>';
return;
}
@@ -401,7 +420,7 @@
for (let k in val) {
rows += `
<tr class="border-b border-gray-800 last:border-0 hover:bg-gray-800/50 transition">
<td class="py-2.5 px-3 text-xs font-bold text-gray-500 uppercase tracking-widest w-1/3">${k}</td>
<td class="py-2.5 px-3 text-xs font-bold dark:text-gray-500 text-gray-400 uppercase tracking-widest w-1/3">${k}</td>
<td class="py-2.5 px-3 text-sm font-mono text-gray-300 w-2/3">${val[k]}</td>
</tr>`;
}
@@ -414,9 +433,9 @@
<div class="group border-b border-gray-800/50 last:border-0">
<button class="w-full px-5 py-4 text-left font-bold text-gray-300 hover:bg-gray-800 transition focus:outline-none flex justify-between items-center" onclick="this.nextElementSibling.classList.toggle('hidden')">
<span class="uppercase tracking-widest text-sm">${key}</span>
<svg class="w-4 h-4 text-gray-500 transform group-focus-within:rotate-180 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
<svg class="w-4 h-4 dark:text-gray-500 text-gray-400 transform group-focus-within:rotate-180 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path></svg>
</button>
<div class="bg-gray-900/80 hidden">
<div class="dark:bg-gray-900 bg-gray-50/80 hidden">
${contentHtml}
</div>
</div>`;
@@ -427,13 +446,13 @@
function renderAudit(data) {
const container = document.getElementById('audit-timeline');
if (!data || !data.slice) {
container.innerHTML = '<p class="text-sm text-gray-500 italic">Erreur de lecture des logs</p>';
container.innerHTML = '<p class="text-sm dark:text-gray-500 text-gray-400 italic">Erreur de lecture des logs</p>';
return;
}
const sliced = data.slice(0, 15);
if (sliced.length === 0) {
container.innerHTML = '<p class="text-sm text-gray-500 italic">Aucun log récent</p>';
container.innerHTML = '<p class="text-sm dark:text-gray-500 text-gray-400 italic">Aucun log récent</p>';
return;
}
@@ -445,9 +464,9 @@
<div class="absolute -left-2 mt-1.5 w-4 h-4 rounded-full ${style.bg} border-4 border-gray-900 shadow-sm z-10"></div>
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-baseline gap-1 mb-1">
<span class="hf-tag ${style.tag} w-max">${log.agent_name}</span>
<span class="text-[10px] font-mono text-gray-500 uppercase tracking-wider">${relativeTime(log.timestamp)}</span>
<span class="text-[10px] font-mono dark:text-gray-500 text-gray-400 uppercase tracking-wider">${relativeTime(log.timestamp)}</span>
</div>
<p class="text-sm text-gray-400 mt-1">Scope ciblé : <strong class="text-gray-200 uppercase tracking-wide text-xs">${log.scope}</strong></p>
<p class="text-sm dark:text-gray-400 dark:text-gray-500 text-gray-400 mt-1">Scope ciblé : <strong class="text-gray-200 uppercase tracking-wide text-xs">${log.scope}</strong></p>
</div>`;
});
container.innerHTML = html;