feat(infra): add pihole rule to infra scope
This commit is contained in:
@@ -4,26 +4,26 @@
|
||||
<div class="mb-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-white">Audit Logs</h1>
|
||||
<p class="text-gray-400 mt-2">History of API and MCP accesses by agents.</p>
|
||||
<p class="dark:text-gray-400 text-gray-500 mt-2">History of API and MCP accesses by agents.</p>
|
||||
</div>
|
||||
<a href="/dashboard" class="text-gray-400 hover:text-white">← Back to Dashboard</a>
|
||||
<a href="/dashboard" class="dark:text-gray-400 text-gray-500 hover:text-white">← Back to Dashboard</a>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-800 rounded-lg shadow border border-gray-700 p-6">
|
||||
<div class="dark:bg-gray-800 bg-gray-100 rounded-lg shadow border dark:border-gray-700 border-gray-200 p-6">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-700">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Time</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Agent</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Scope / Action</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">IP Address</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium dark:text-gray-400 text-gray-500 uppercase tracking-wider">Time</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium dark:text-gray-400 text-gray-500 uppercase tracking-wider">Agent</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium dark:text-gray-400 text-gray-500 uppercase tracking-wider">Scope / Action</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium dark:text-gray-400 text-gray-500 uppercase tracking-wider">IP Address</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-700">
|
||||
{% for log in logs %}
|
||||
<tr class="hover:bg-gray-750 transition">
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-400">{{ log.timestamp }}</td>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm dark:text-gray-400 text-gray-500">{{ log.timestamp }}</td>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm font-medium text-gray-200">{{ log.agent_name }}</td>
|
||||
<td class="px-4 py-4 whitespace-nowrap text-sm">
|
||||
{% if 'FORBIDDEN' in log.scope %}
|
||||
|
||||
+222
-29
@@ -1,44 +1,204 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="dark">
|
||||
<html lang="fr" class="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}context-hub | Nyora Infrastructure{% endblock %}</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
nyora: '#d4a01a'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: { extend: { colors: { nyora: "#d4a01a", "nyora-dark": "#a07810" } } }
|
||||
}
|
||||
</script>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
body { font-family: "Inter", sans-serif; }
|
||||
|
||||
/* ── BACKGROUNDS ── */
|
||||
.bg-app {
|
||||
background: #0a0e1a;
|
||||
background-image:
|
||||
radial-gradient(ellipse at 15% 40%, rgba(29,78,216,0.12) 0%, transparent 55%),
|
||||
radial-gradient(ellipse at 85% 15%, rgba(212,160,26,0.08) 0%, transparent 50%),
|
||||
radial-gradient(ellipse at 55% 85%, rgba(109,40,217,0.08) 0%, transparent 50%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
/* HF Storage light mode : fond blanc pur + ticker + sections */
|
||||
html:not(.dark) body {
|
||||
background: #ffffff;
|
||||
}
|
||||
html:not(.dark) body::before {
|
||||
content: '';
|
||||
position: fixed; inset: 0; pointer-events: none; z-index: -1;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
/* ── GLASS ── */
|
||||
.glass-dark {
|
||||
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);
|
||||
}
|
||||
.glass-light {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e2e8f0;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 16px rgba(0,0,0,0.04);
|
||||
}
|
||||
|
||||
/* ── CARD 4D ── */
|
||||
.card-4d {
|
||||
border-radius: 1rem;
|
||||
overflow: hidden;
|
||||
transition: all 0.35s cubic-bezier(0.4,0,0.2,1);
|
||||
transform-style: preserve-3d;
|
||||
position: relative;
|
||||
}
|
||||
.card-4d::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;
|
||||
}
|
||||
.card-4d:hover {
|
||||
transform: translateY(-5px) perspective(800px) rotateX(1.5deg) rotateY(-0.5deg);
|
||||
}
|
||||
.dark .card-4d:hover {
|
||||
box-shadow: 0 24px 64px rgba(0,0,0,0.5), 0 0 0 1px rgba(212,160,26,0.2);
|
||||
}
|
||||
.light .card-4d:hover, html:not(.dark) .card-4d:hover {
|
||||
box-shadow: 0 24px 64px rgba(99,102,241,0.15), 0 0 0 1px rgba(212,160,26,0.3);
|
||||
}
|
||||
|
||||
/* ── NAV ── */
|
||||
.nav-bar {
|
||||
position: sticky; top: 0; z-index: 100;
|
||||
backdrop-filter: blur(24px) saturate(200%);
|
||||
-webkit-backdrop-filter: blur(24px) saturate(200%);
|
||||
}
|
||||
|
||||
/* ── TOGGLE THEME ── */
|
||||
.theme-btn {
|
||||
display: flex; align-items: center; gap: 6px;
|
||||
padding: 6px 14px;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.03em;
|
||||
border: 1.5px solid rgba(212,160,26,0.6);
|
||||
color: #d4a01a;
|
||||
background: rgba(212,160,26,0.1);
|
||||
transition: all 0.2s;
|
||||
user-select: none;
|
||||
}
|
||||
.theme-btn:hover { background: rgba(212,160,26,0.2); border-color: #d4a01a; transform: scale(1.04); }
|
||||
.theme-btn .icon { font-size: 0.9rem; }
|
||||
|
||||
/* ── NYORA FOOTER ── */
|
||||
.nyora-footer { text-align: center; position: relative; padding: 0; }
|
||||
.nyora-line-top {
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent, rgba(212,160,26,0.4), #d4a01a, rgba(212,160,26,0.4), transparent);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
.nyora-brand { display: flex; align-items: center; justify-content: center; gap: 0.6rem; margin-bottom: 0.35rem; }
|
||||
.nyora-dot { width: 5px; height: 5px; background: #d4a01a; border-radius: 50%; }
|
||||
.nyora-name { font-size: 0.82rem; font-weight: 800; letter-spacing: 0.4em; color: #d4a01a; font-family: Georgia, serif; }
|
||||
.nyora-tag { font-size: 0.7rem; letter-spacing: 0.08em; font-style: italic; margin-bottom: 0.2rem; }
|
||||
.nyora-year { font-size: 0.65rem; letter-spacing: 0.05em; }
|
||||
|
||||
/* ── HF TICKER ── */
|
||||
.hf-ticker {
|
||||
display: none;
|
||||
overflow: hidden;
|
||||
background: #1a1a2e;
|
||||
color: rgba(255,255,255,0.35);
|
||||
font-family: monospace;
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.08em;
|
||||
padding: 7px 0;
|
||||
white-space: nowrap;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.05);
|
||||
}
|
||||
html:not(.dark) .hf-ticker { display: block; }
|
||||
.hf-ticker-inner {
|
||||
display: inline-block;
|
||||
animation: ticker 28s linear infinite;
|
||||
}
|
||||
@keyframes ticker {
|
||||
0% { transform: translateX(0); }
|
||||
100% { transform: translateX(-50%); }
|
||||
}
|
||||
/* nav clair HF */
|
||||
html:not(.dark) nav.nav-bar {
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
|
||||
}
|
||||
html:not(.dark) body {
|
||||
background: #f8fafc;
|
||||
color: #0f172a;
|
||||
}
|
||||
/* section headers colorés style HF en mode clair */
|
||||
html:not(.dark) .hf-header {
|
||||
}
|
||||
html:not(.dark) .hf-tag {
|
||||
filter: brightness(0.85) saturate(1.2);
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
|
||||
<script>
|
||||
(function(){
|
||||
var t = localStorage.getItem("ctx-theme") || "dark";
|
||||
if(t === "light") document.documentElement.classList.remove("dark");
|
||||
else document.documentElement.classList.add("dark");
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col font-sans">
|
||||
|
||||
<body id="app-body" class="bg-app min-h-screen flex flex-col transition-all duration-300">
|
||||
|
||||
< HF-style ticker (mode clair uniquement) -->
|
||||
<div class="hf-ticker" aria-hidden="true">
|
||||
<span class="hf-ticker-inner">
|
||||
+ = · ( ~ @ · # % · & * ? · / : · ; < > · [ ] · { }
|
||||
context-hub · NYORA INFRASTRUCTURE ·
|
||||
infra · llm · nyora · perso · tt ·
|
||||
+ = · ( ~ @ · # % · & * ? · / : · ; < > · [ ] · { }
|
||||
context-hub · NYORA INFRASTRUCTURE ·
|
||||
infra · llm · nyora · perso · tt ·
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{% if request.url.path != "/login" %}
|
||||
<nav class="bg-gray-800 border-b border-gray-700">
|
||||
<nav class="nav-bar dark:bg-gray-950/90 bg-white/90 dark:border-white/5 border-gray-200/80 border-b">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0 text-nyora font-bold text-xl tracking-wider">
|
||||
CONTEXT-HUB
|
||||
</div>
|
||||
<div class="hidden md:block">
|
||||
<div class="ml-10 flex items-baseline space-x-4">
|
||||
<a href="/dashboard" class="text-gray-300 hover:text-white hover:bg-gray-700 px-3 py-2 rounded-md text-sm font-medium">Dashboard</a>
|
||||
<a href="/audit" class="text-gray-300 hover:text-white hover:bg-gray-700 px-3 py-2 rounded-md text-sm font-medium">Audit Logs</a>
|
||||
<a href="/keys" class="text-gray-300 hover:text-white hover:bg-gray-700 px-3 py-2 rounded-md text-sm font-medium">API Keys</a>
|
||||
<div class="flex items-center justify-between h-14">
|
||||
<div class="flex items-center gap-8">
|
||||
<a href="/dashboard" class="flex items-center gap-2 no-underline group">
|
||||
<div class="w-7 h-7 rounded-lg flex items-center justify-center"
|
||||
style="background:linear-gradient(135deg,#d4a01a,#f0b429)">
|
||||
<span class="text-xs font-black text-gray-900">C</span>
|
||||
</div>
|
||||
<span class="font-black text-sm tracking-widest dark:text-white text-gray-900">CONTEXT<span class="text-nyora">-HUB</span></span>
|
||||
</a>
|
||||
<div class="hidden md:flex items-center gap-1">
|
||||
<a href="/dashboard" class="px-3 py-1.5 rounded-lg text-xs font-medium dark:text-gray-400 text-gray-600 dark:hover:text-white hover:text-gray-900 dark:hover:bg-white/5 hover:bg-gray-100 transition-all">Dashboard</a>
|
||||
<a href="/audit" class="px-3 py-1.5 rounded-lg text-xs font-medium dark:text-gray-400 text-gray-600 dark:hover:text-white hover:text-gray-900 dark:hover:bg-white/5 hover:bg-gray-100 transition-all">Audit</a>
|
||||
<a href="/keys" class="px-3 py-1.5 rounded-lg text-xs font-medium dark:text-gray-400 text-gray-600 dark:hover:text-white hover:text-gray-900 dark:hover:bg-white/5 hover:bg-gray-100 transition-all">API Keys</a>
|
||||
<a href="/docs" class="px-3 py-1.5 rounded-lg text-xs font-medium dark:text-gray-400 text-gray-600 dark:hover:text-white hover:text-gray-900 dark:hover:bg-white/5 hover:bg-gray-100 transition-all">Docs</a>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a href="/auth/logout" class="text-gray-400 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Logout</a>
|
||||
<div class="flex items-center gap-3">
|
||||
<button class="theme-btn" onclick="toggleTheme()" id="theme-btn">
|
||||
<span class="icon" id="theme-icon">☀️</span>
|
||||
<span id="theme-label">Clair</span>
|
||||
</button>
|
||||
<a href="/auth/logout" class="px-3 py-1.5 rounded-lg text-xs font-medium dark:text-gray-400 text-gray-600 dark:hover:text-red-400 hover:text-red-500 transition-all">Déconnexion</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -49,10 +209,43 @@
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="bg-gray-900 py-6 border-t border-gray-800 text-center">
|
||||
<p class="text-nyora font-medium uppercase tracking-widest text-sm">Nyora</p>
|
||||
<p class="text-gray-500 text-xs mt-1">Crafted with precision | 2026</p>
|
||||
<footer class="nyora-footer mt-12">
|
||||
<div class="nyora-line-top"></div>
|
||||
<div class="pb-8">
|
||||
<div class="nyora-brand">
|
||||
<span class="nyora-dot"></span>
|
||||
<span class="nyora-name">NYORA</span>
|
||||
<span class="nyora-dot"></span>
|
||||
</div>
|
||||
<div class="nyora-tag dark:text-gray-500 text-gray-400">Crafted with precision · Built for excellence</div>
|
||||
<div class="nyora-year dark:text-gray-600 text-gray-400">© 2026</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script>
|
||||
function updateThemeUI(isDark) {
|
||||
var icon = document.getElementById("theme-icon");
|
||||
var label = document.getElementById("theme-label");
|
||||
if (!icon) return;
|
||||
if (isDark) { icon.textContent = "☀️"; label.textContent = "Clair"; }
|
||||
else { icon.textContent = "🌙"; label.textContent = "Sombre"; }
|
||||
}
|
||||
function toggleTheme() {
|
||||
var html = document.documentElement;
|
||||
var isDark = html.classList.contains("dark");
|
||||
if (isDark) {
|
||||
html.classList.remove("dark");
|
||||
localStorage.setItem("ctx-theme","light");
|
||||
updateThemeUI(false);
|
||||
} else {
|
||||
html.classList.add("dark");
|
||||
localStorage.setItem("ctx-theme","dark");
|
||||
updateThemeUI(true);
|
||||
}
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", function(){
|
||||
updateThemeUI(document.documentElement.classList.contains("dark"));
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="dark">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}context-hub | Nyora Infrastructure{% endblock %}</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script>
|
||||
tailwind.config = {
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
nyora: '#d4a01a'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body class="bg-gray-900 text-gray-100 min-h-screen flex flex-col font-sans">
|
||||
|
||||
{% if request.url.path != "/login" %}
|
||||
<nav class="bg-gray-800 border-b border-gray-700">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div class="flex items-center justify-between h-16">
|
||||
<div class="flex items-center">
|
||||
<div class="flex-shrink-0 text-nyora font-bold text-xl tracking-wider">
|
||||
CONTEXT-HUB
|
||||
</div>
|
||||
<div class="hidden md:block">
|
||||
<div class="ml-10 flex items-baseline space-x-4">
|
||||
<a href="/dashboard" class="text-gray-300 hover:text-white hover:bg-gray-700 px-3 py-2 rounded-md text-sm font-medium">Dashboard</a>
|
||||
<a href="/audit" class="text-gray-300 hover:text-white hover:bg-gray-700 px-3 py-2 rounded-md text-sm font-medium">Audit Logs</a>
|
||||
<a href="/keys" class="text-gray-300 hover:text-white hover:bg-gray-700 px-3 py-2 rounded-md text-sm font-medium">API Keys</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<a href="/auth/logout" class="text-gray-400 hover:text-white px-3 py-2 rounded-md text-sm font-medium">Logout</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
<main class="flex-grow w-full max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer class="bg-gray-900 py-6 border-t border-gray-800 text-center">
|
||||
<p class="text-nyora font-medium uppercase tracking-widest text-sm">Nyora</p>
|
||||
<p class="text-gray-500 text-xs mt-1">Crafted with precision | 2026</p>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
+57
-38
@@ -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;
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
<div class="mb-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-white uppercase">{{ scope }} Scope Editor</h1>
|
||||
<p class="text-gray-400 mt-2">Edit rules for the <span class="font-bold text-gray-200">{{ scope }}</span> scope (JSON format).</p>
|
||||
<p class="dark:text-gray-400 text-gray-500 mt-2">Edit rules for the <span class="font-bold text-gray-200">{{ scope }}</span> scope (JSON format).</p>
|
||||
</div>
|
||||
<a href="/dashboard" class="text-gray-400 hover:text-white">← Back to Dashboard</a>
|
||||
<a href="/dashboard" class="dark:text-gray-400 text-gray-500 hover:text-white">← Back to Dashboard</a>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-800 rounded-lg shadow border border-gray-700 p-6">
|
||||
<div class="dark:bg-gray-800 bg-gray-100 rounded-lg shadow border dark:border-gray-700 border-gray-200 p-6">
|
||||
<div id="alert-box" class="hidden mb-4 p-4 rounded-md text-sm"></div>
|
||||
<form id="editor-form" class="space-y-4">
|
||||
<div>
|
||||
<textarea id="json-editor" rows="20" class="w-full bg-gray-900 text-gray-100 font-mono text-sm p-4 rounded-md border border-gray-600 focus:border-nyora focus:ring-1 focus:ring-nyora transition"></textarea>
|
||||
<textarea id="json-editor" rows="20" class="w-full dark:bg-gray-900 bg-white dark:text-gray-100 text-gray-900 font-mono text-sm p-4 rounded-md border border-gray-600 focus:border-nyora focus:ring-1 focus:ring-nyora transition"></textarea>
|
||||
</div>
|
||||
<div class="flex justify-end">
|
||||
<button type="button" onclick="saveRules()" class="px-6 py-2 bg-nyora text-gray-900 font-medium rounded-md hover:bg-yellow-500 transition shadow-sm">Save Changes</button>
|
||||
|
||||
+7
-7
@@ -4,21 +4,21 @@
|
||||
<div class="mb-6 flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-white">API Keys</h1>
|
||||
<p class="text-gray-400 mt-2">Manage access keys for all agents.</p>
|
||||
<p class="dark:text-gray-400 text-gray-500 mt-2">Manage access keys for all agents.</p>
|
||||
</div>
|
||||
<a href="/dashboard" class="text-gray-400 hover:text-white">← Back to Dashboard</a>
|
||||
<a href="/dashboard" class="dark:text-gray-400 text-gray-500 hover:text-white">← Back to Dashboard</a>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-800 rounded-lg shadow border border-gray-700 p-6">
|
||||
<div class="dark:bg-gray-800 bg-gray-100 rounded-lg shadow border dark:border-gray-700 border-gray-200 p-6">
|
||||
<div id="alert-box" class="hidden mb-4 p-4 rounded-md text-sm"></div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-700">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Agent</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">API Key</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Last Used</th>
|
||||
<th class="px-4 py-3 text-right text-xs font-medium text-gray-400 uppercase tracking-wider">Actions</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium dark:text-gray-400 text-gray-500 uppercase tracking-wider">Agent</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium dark:text-gray-400 text-gray-500 uppercase tracking-wider">API Key</th>
|
||||
<th class="px-4 py-3 text-left text-xs font-medium dark:text-gray-400 text-gray-500 uppercase tracking-wider">Last Used</th>
|
||||
<th class="px-4 py-3 text-right text-xs font-medium dark:text-gray-400 text-gray-500 uppercase tracking-wider">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-700">
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="flex items-center justify-center h-[70vh]">
|
||||
<div class="bg-gray-800 p-8 rounded-lg shadow-xl w-full max-w-md border border-gray-700">
|
||||
<div class="flex items-center justify-center min-h-[80vh]">
|
||||
<div class="login-card p-8 w-full max-w-md">
|
||||
<h2 class="text-2xl font-bold text-nyora mb-6 text-center">Nyora Infrastructure</h2>
|
||||
<form action="/auth/login" method="POST" class="space-y-6">
|
||||
<div>
|
||||
<label for="username" class="block text-sm font-medium text-gray-400">Username</label>
|
||||
<label for="username" class="block text-sm font-medium dark:text-gray-400 text-gray-500">Username</label>
|
||||
<input type="text" id="username" name="username" placeholder="Identifiant" required
|
||||
class="mt-1 block w-full px-4 py-3 bg-gray-900 border border-gray-600 rounded-md text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-nyora focus:border-transparent transition">
|
||||
class="mt-1 block w-full px-4 py-3 dark:bg-gray-900 bg-white border border-gray-600 rounded-md text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-nyora focus:border-transparent transition">
|
||||
</div>
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-medium text-gray-400">Password</label>
|
||||
<label for="password" class="block text-sm font-medium dark:text-gray-400 text-gray-500">Password</label>
|
||||
<input type="password" id="password" name="password" placeholder="Mot de passe" required
|
||||
class="mt-1 block w-full px-4 py-3 bg-gray-900 border border-gray-600 rounded-md text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-nyora focus:border-transparent transition">
|
||||
class="mt-1 block w-full px-4 py-3 dark:bg-gray-900 bg-white border border-gray-600 rounded-md text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-nyora focus:border-transparent transition">
|
||||
</div>
|
||||
<button type="submit"
|
||||
class="w-full flex justify-center py-3 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-gray-900 bg-nyora hover:bg-yellow-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-nyora focus:ring-offset-gray-900 transition">
|
||||
|
||||
Reference in New Issue
Block a user