feat: cookie-based auth, SSR dashboard, JS-optional login
This commit is contained in:
@@ -152,7 +152,6 @@
|
||||
</main>
|
||||
|
||||
<script>
|
||||
if (!requireAuth()) throw 'auth';
|
||||
|
||||
const monitorId = window.location.pathname.split('/').pop();
|
||||
let editQuery = null;
|
||||
|
||||
@@ -12,17 +12,39 @@
|
||||
</div>
|
||||
|
||||
<div id="monitors-list" class="space-y-3">
|
||||
<div class="text-center py-16 text-gray-600">Loading...</div>
|
||||
<% if (it.monitors && it.monitors.length === 0) { %>
|
||||
<div id="empty-state" class="text-center py-16">
|
||||
<p class="text-gray-500 mb-4">No monitors yet</p>
|
||||
<a href="/dashboard/monitors/new" class="bg-blue-600 hover:bg-blue-500 text-white text-sm font-medium px-6 py-3 rounded-lg transition-colors inline-block">Create your first monitor</a>
|
||||
</div>
|
||||
<% } else if (it.monitors) { %>
|
||||
<% it.monitors.forEach(function(m) { %>
|
||||
<a href="/dashboard/monitors/<%= m.id %>" data-monitor-id="<%= m.id %>" class="block bg-gray-900 hover:bg-gray-800/80 border border-gray-800 rounded-xl p-4 transition-colors group">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-3 min-w-0">
|
||||
<span class="status-dot w-2.5 h-2.5 rounded-full <%= m.last_ping == null ? 'bg-gray-600' : (m.last_ping.up ? 'bg-green-500' : 'bg-red-500') %>"></span>
|
||||
<div class="min-w-0">
|
||||
<div class="font-medium text-gray-100 group-hover:text-white truncate"><%= m.name %></div>
|
||||
<div class="text-xs text-gray-500 truncate"><%= m.url %></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-6 shrink-0 ml-4">
|
||||
<div class="text-right">
|
||||
<div class="text-sm text-gray-300 stat-latency"><%= m.last_ping ? m.last_ping.latency_ms + 'ms' : '—' %></div>
|
||||
<div class="text-xs text-gray-500 stat-last"><%= m.last_ping ? '<span class="timestamp" data-ts="' + new Date(m.last_ping.checked_at).getTime() + '">just now</span>' : 'no pings' %></div>
|
||||
</div>
|
||||
<div class="text-xs px-2 py-1 rounded <%= m.enabled ? 'bg-gray-800 text-gray-400' : 'bg-yellow-900/30 text-yellow-500' %>"><%= m.enabled ? m.interval_s + 's' : 'paused' %></div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<% }) %>
|
||||
<% } else { %>
|
||||
<div class="text-center py-16 text-gray-600">Loading...</div>
|
||||
</div>
|
||||
|
||||
<div id="empty-state" class="hidden text-center py-16">
|
||||
<p class="text-gray-500 mb-4">No monitors yet</p>
|
||||
<a href="/dashboard/monitors/new" class="bg-blue-600 hover:bg-blue-500 text-white text-sm font-medium px-6 py-3 rounded-lg transition-colors inline-block">Create your first monitor</a>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
if (!requireAuth()) throw 'auth';
|
||||
|
||||
async function load() {
|
||||
try {
|
||||
|
||||
@@ -90,7 +90,6 @@
|
||||
</main>
|
||||
|
||||
<script>
|
||||
if (!requireAuth()) throw 'auth';
|
||||
|
||||
let currentQuery = null;
|
||||
// Show body section for non-GET methods
|
||||
|
||||
@@ -84,14 +84,10 @@
|
||||
|
||||
|
||||
<script>
|
||||
if (!requireAuth()) throw 'auth';
|
||||
|
||||
const key = localStorage.getItem('pingql_key');
|
||||
|
||||
async function loadSettings() {
|
||||
const data = await api('/account/settings');
|
||||
|
||||
document.getElementById('primary-key').textContent = key;
|
||||
document.getElementById('primary-key').textContent = data.account_id;
|
||||
document.getElementById('created-at').textContent = new Date(data.created_at).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
|
||||
|
||||
if (data.has_email) {
|
||||
@@ -155,7 +151,8 @@
|
||||
async function confirmReset() {
|
||||
if (!confirm('Rotate your primary key?\n\nYour current key will stop working immediately. Make sure to copy the new one.')) return;
|
||||
const data = await api('/account/reset-key', { method: 'POST', body: {} });
|
||||
localStorage.setItem('pingql_key', data.key);
|
||||
// Re-auth with new key (updates cookie)
|
||||
await fetch('/account/login', { method: 'POST', credentials: 'same-origin', headers: {'Content-Type':'application/json'}, body: JSON.stringify({ key: data.key }) });
|
||||
document.getElementById('primary-key').textContent = data.key;
|
||||
location.reload();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user