🔱 GOD PANEL: Visual diagnostics dashboard

Features:
- Completely standalone (no Directus, no middleware, no redirects)
- Live service status for all 4 containers
- SQL Console for direct database queries
- Quick Actions (check sites, count articles, etc.)
- Table browser with row counts
- Memory & performance metrics
- Auto-refresh option (5s interval)
- Raw health data viewer

Tech:
- Pure React via ESM CDN imports
- Tailwind CDN (no build dependency)
- Dark theme with gold accents
- Works even when everything else is broken

URL: /god
This commit is contained in:
cawcenter
2025-12-14 15:17:14 -05:00
parent acc4d2fe1b
commit 3cd7073ecc

View File

@@ -0,0 +1,367 @@
---
/**
* 🔱 GOD PANEL - System Diagnostics Dashboard
*
* This page is COMPLETELY STANDALONE:
* - No middleware
* - No Directus dependency
* - No redirects
* - Works even when everything else is broken
*/
export const prerender = false;
---
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🔱 God Panel - Spark Platform</title>
<meta name="robots" content="noindex, nofollow">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
darkMode: 'class',
theme: {
extend: {
colors: {
god: {
gold: '#FFD700',
dark: '#0a0a0a',
card: '#111111',
border: '#333333'
}
}
}
}
}
</script>
<style>
@keyframes pulse-gold {
0%, 100% { box-shadow: 0 0 0 0 rgba(255, 215, 0, 0.4); }
50% { box-shadow: 0 0 20px 10px rgba(255, 215, 0, 0.1); }
}
.pulse-gold { animation: pulse-gold 2s infinite; }
.status-healthy { color: #22c55e; }
.status-unhealthy { color: #ef4444; }
.status-warning { color: #eab308; }
pre { white-space: pre-wrap; word-wrap: break-word; }
</style>
</head>
<body class="bg-god-dark text-white min-h-screen">
<div id="god-panel"></div>
<script type="module">
import React from 'https://esm.sh/react@18';
import ReactDOM from 'https://esm.sh/react-dom@18/client';
const { useState, useEffect, useCallback } = React;
const h = React.createElement;
// API Helper
const api = {
async get(endpoint) {
const token = localStorage.getItem('godToken') || '';
const res = await fetch(`/api/god/${endpoint}`, {
headers: { 'X-God-Token': token }
});
return res.json();
},
async post(endpoint, data) {
const token = localStorage.getItem('godToken') || '';
const res = await fetch(`/api/god/${endpoint}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-God-Token': token
},
body: JSON.stringify(data)
});
return res.json();
}
};
// Status Badge Component
function StatusBadge({ status }) {
const isHealthy = status?.includes('✅') || status === 'healthy' || status === 'connected';
const isWarning = status?.includes('⚠️');
const className = isHealthy ? 'status-healthy' : isWarning ? 'status-warning' : 'status-unhealthy';
return h('span', { className: `font-bold ${className}` }, status || 'Unknown');
}
// Service Card Component
function ServiceCard({ name, data, icon }) {
const status = data?.status || 'Unknown';
const isHealthy = status?.includes('✅') || status?.includes('healthy');
return h('div', {
className: `bg-god-card border border-god-border rounded-xl p-4 ${isHealthy ? '' : 'border-red-500/50'}`
}, [
h('div', { className: 'flex items-center justify-between mb-2' }, [
h('div', { className: 'flex items-center gap-2' }, [
h('span', { className: 'text-2xl' }, icon),
h('span', { className: 'font-semibold text-lg' }, name)
]),
h(StatusBadge, { status })
]),
data?.latency_ms && h('div', { className: 'text-sm text-gray-400' },
`Latency: ${data.latency_ms}ms`
),
data?.error && h('div', { className: 'text-sm text-red-400 mt-1' },
`Error: ${data.error}`
)
]);
}
// SQL Console Component
function SQLConsole() {
const [query, setQuery] = useState('SELECT * FROM sites LIMIT 5;');
const [result, setResult] = useState(null);
const [loading, setLoading] = useState(false);
const execute = async () => {
setLoading(true);
try {
const data = await api.post('sql', { query });
setResult(data);
} catch (err) {
setResult({ error: err.message });
}
setLoading(false);
};
return h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4' }, [
h('h3', { className: 'text-lg font-semibold mb-3 flex items-center gap-2' }, [
'🗄️ SQL Console'
]),
h('textarea', {
className: 'w-full bg-black border border-god-border rounded-lg p-3 font-mono text-sm text-green-400 mb-3',
rows: 4,
value: query,
onChange: e => setQuery(e.target.value),
placeholder: 'Enter SQL query...'
}),
h('button', {
className: 'bg-god-gold text-black font-bold px-4 py-2 rounded-lg hover:bg-yellow-400 disabled:opacity-50',
onClick: execute,
disabled: loading
}, loading ? 'Executing...' : 'Execute SQL'),
result && h('div', { className: 'mt-4' }, [
result.error ?
h('div', { className: 'text-red-400 font-mono text-sm' }, `Error: ${result.error}`) :
h('div', {}, [
h('div', { className: 'text-sm text-gray-400 mb-2' },
`${result.rowCount || 0} rows returned`
),
h('pre', {
className: 'bg-black rounded-lg p-3 overflow-auto max-h-64 text-xs font-mono text-gray-300'
}, JSON.stringify(result.rows, null, 2))
])
])
]);
}
// Tables List Component
function TablesList({ tables }) {
if (!tables?.tables) return null;
const customTables = tables.tables.filter(t => !t.name.startsWith('directus_'));
const systemTables = tables.tables.filter(t => t.name.startsWith('directus_'));
return h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4' }, [
h('h3', { className: 'text-lg font-semibold mb-3' },
`📊 Database Tables (${tables.total})`
),
h('div', { className: 'grid grid-cols-2 gap-4' }, [
h('div', {}, [
h('h4', { className: 'text-sm font-semibold text-god-gold mb-2' },
`Custom Tables (${customTables.length})`
),
h('div', { className: 'space-y-1 max-h-48 overflow-auto' },
customTables.map(t =>
h('div', {
key: t.name,
className: 'text-xs font-mono flex justify-between bg-black/50 px-2 py-1 rounded'
}, [
h('span', {}, t.name),
h('span', { className: 'text-gray-500' }, `${t.rows} rows`)
])
)
)
]),
h('div', {}, [
h('h4', { className: 'text-sm font-semibold text-gray-400 mb-2' },
`Directus System (${systemTables.length})`
),
h('div', { className: 'text-xs text-gray-500' },
systemTables.length + ' system tables'
)
])
])
]);
}
// Quick Actions Component
function QuickActions() {
const actions = [
{ label: 'Check Sites', query: 'SELECT id, name, url, status FROM sites LIMIT 10' },
{ label: 'Count Articles', query: 'SELECT COUNT(*) as count FROM generated_articles' },
{ label: 'Active Connections', query: 'SELECT count(*) FROM pg_stat_activity' },
{ label: 'DB Size', query: "SELECT pg_size_pretty(pg_database_size(current_database())) as size" },
];
const [result, setResult] = useState(null);
const run = async (query) => {
const data = await api.post('sql', { query });
setResult(data);
};
return h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4' }, [
h('h3', { className: 'text-lg font-semibold mb-3' }, '⚡ Quick Actions'),
h('div', { className: 'flex flex-wrap gap-2' },
actions.map(a =>
h('button', {
key: a.label,
className: 'bg-god-border hover:bg-god-gold hover:text-black px-3 py-1 rounded text-sm transition-colors',
onClick: () => run(a.query)
}, a.label)
)
),
result && h('pre', {
className: 'mt-3 bg-black rounded-lg p-3 text-xs font-mono text-gray-300 overflow-auto max-h-32'
}, JSON.stringify(result.rows || result, null, 2))
]);
}
// Main God Panel Component
function GodPanel() {
const [services, setServices] = useState(null);
const [health, setHealth] = useState(null);
const [tables, setTables] = useState(null);
const [loading, setLoading] = useState(true);
const [autoRefresh, setAutoRefresh] = useState(false);
const [lastUpdate, setLastUpdate] = useState(null);
const refresh = useCallback(async () => {
try {
const [svc, hlth, tbl] = await Promise.all([
api.get('services'),
api.get('health'),
api.get('tables')
]);
setServices(svc);
setHealth(hlth);
setTables(tbl);
setLastUpdate(new Date().toLocaleTimeString());
} catch (err) {
console.error('Refresh failed:', err);
}
setLoading(false);
}, []);
useEffect(() => {
refresh();
if (autoRefresh) {
const interval = setInterval(refresh, 5000);
return () => clearInterval(interval);
}
}, [refresh, autoRefresh]);
return h('div', { className: 'max-w-6xl mx-auto p-6' }, [
// Header
h('div', { className: 'flex items-center justify-between mb-8' }, [
h('div', {}, [
h('h1', { className: 'text-3xl font-bold flex items-center gap-3' }, [
h('span', { className: 'text-god-gold pulse-gold inline-block' }, '🔱'),
'God Panel'
]),
h('p', { className: 'text-gray-400 mt-1' },
'System Diagnostics & Emergency Access'
)
]),
h('div', { className: 'flex items-center gap-4' }, [
h('label', { className: 'flex items-center gap-2 text-sm' }, [
h('input', {
type: 'checkbox',
checked: autoRefresh,
onChange: e => setAutoRefresh(e.target.checked),
className: 'rounded'
}),
'Auto-refresh (5s)'
]),
h('button', {
className: 'bg-god-gold text-black font-bold px-4 py-2 rounded-lg hover:bg-yellow-400',
onClick: refresh
}, '🔄 Refresh'),
lastUpdate && h('span', { className: 'text-xs text-gray-500' },
`Last: ${lastUpdate}`
)
])
]),
// Summary Banner
services?.summary && h('div', {
className: `rounded-xl p-4 mb-6 text-center font-bold text-lg ${
services.summary.includes('✅') ? 'bg-green-900/30 border border-green-500/50' :
'bg-red-900/30 border border-red-500/50'
}`
}, services.summary),
// Service Grid
h('div', { className: 'grid grid-cols-2 md:grid-cols-4 gap-4 mb-6' }, [
h(ServiceCard, { name: 'Frontend', data: services?.frontend, icon: '🌐' }),
h(ServiceCard, { name: 'PostgreSQL', data: services?.postgresql, icon: '🐘' }),
h(ServiceCard, { name: 'Redis', data: services?.redis, icon: '🔴' }),
h(ServiceCard, { name: 'Directus', data: services?.directus, icon: '📦' }),
]),
// Memory & Performance
health && h('div', { className: 'grid grid-cols-3 gap-4 mb-6' }, [
h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4 text-center' }, [
h('div', { className: 'text-3xl font-bold text-god-gold' },
health.uptime_seconds ? Math.round(health.uptime_seconds / 60) + 'm' : '-'
),
h('div', { className: 'text-sm text-gray-400' }, 'Uptime')
]),
h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4 text-center' }, [
h('div', { className: 'text-3xl font-bold text-god-gold' },
health.memory?.heap_used_mb ? health.memory.heap_used_mb + 'MB' : '-'
),
h('div', { className: 'text-sm text-gray-400' }, 'Memory Used')
]),
h('div', { className: 'bg-god-card border border-god-border rounded-xl p-4 text-center' }, [
h('div', { className: 'text-3xl font-bold text-god-gold' },
health.total_latency_ms ? health.total_latency_ms + 'ms' : '-'
),
h('div', { className: 'text-sm text-gray-400' }, 'Health Check')
])
]),
// Main Content Grid
h('div', { className: 'grid md:grid-cols-2 gap-6' }, [
h(SQLConsole, {}),
h('div', { className: 'space-y-6' }, [
h(QuickActions, {}),
h(TablesList, { tables })
])
]),
// Raw Health Data
health && h('details', { className: 'mt-6' }, [
h('summary', { className: 'cursor-pointer text-gray-400 hover:text-white' },
'📋 Raw Health Data'
),
h('pre', {
className: 'mt-2 bg-god-card border border-god-border rounded-xl p-4 text-xs font-mono overflow-auto max-h-64'
}, JSON.stringify(health, null, 2))
])
]);
}
// Render
const root = ReactDOM.createRoot(document.getElementById('god-panel'));
root.render(h(GodPanel));
</script>
</body>
</html>