| <!DOCTYPE html>
|
| <html lang="en">
|
| <head>
|
| <meta charset="UTF-8">
|
| <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, maximum-scale=1">
|
| <meta name="theme-color" content="#0a0a0f">
|
| <meta name="apple-mobile-web-app-capable" content="yes">
|
| <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
| <meta name="mobile-web-app-capable" content="yes">
|
| <title>ServerClass · Admin Console</title>
|
|
|
| <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%236366f1'/%3E%3Cpath d='M10 12h12M10 16h12M10 20h8' stroke='%23fff' stroke-width='2.5' stroke-linecap='round'/%3E%3C/svg%3E">
|
|
|
| <link rel="preconnect" href="https://fonts.googleapis.com">
|
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
|
|
|
| <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
| </head>
|
| <body data-unlocked="{{ 'true' if unlocked else 'false' }}">
|
|
|
| |
| |
|
|
| <div id="lockScreen" class="lock {% if unlocked %}lock--hidden{% endif %}">
|
| <div class="lock__bg"></div>
|
| <div class="lock__card">
|
| <div class="lock__logo">
|
| <div class="lock__logo-mark">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
| <rect x="3" y="11" width="18" height="11" rx="2"/>
|
| <path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
| </svg>
|
| </div>
|
| <div class="lock__brand">
|
| <div class="lock__brand-name">ServerClass</div>
|
| <div class="lock__brand-sub">Admin Console</div>
|
| </div>
|
| </div>
|
|
|
| <h1 class="lock__title">Welcome back</h1>
|
| <p class="lock__sub">Enter your master password to unlock the dashboard.</p>
|
|
|
| <form id="unlockForm" class="lock__form" autocomplete="off">
|
| <div class="lock__field">
|
| <input
|
| type="password"
|
| id="masterPassword"
|
| class="lock__input"
|
| placeholder="Master password"
|
| autocomplete="current-password"
|
| spellcheck="false"
|
| required>
|
| <button type="button" class="lock__toggle" id="togglePw" aria-label="Show password">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/>
|
| <circle cx="12" cy="12" r="3"/>
|
| </svg>
|
| </button>
|
| </div>
|
|
|
| <button type="submit" class="lock__submit" id="unlockBtn">
|
| <span class="lock__submit-label">Unlock</span>
|
| <svg class="lock__submit-arrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
| <path d="M5 12h14M12 5l7 7-7 7"/>
|
| </svg>
|
| </button>
|
|
|
| <div id="lockError" class="lock__error"></div>
|
| </form>
|
|
|
| <div class="lock__footer">
|
| <span class="dot"></span>
|
| <span class="mono">Secure · End-to-end signed session</span>
|
| </div>
|
| </div>
|
| </div>
|
|
|
| |
| |
|
|
| <div id="app" class="app {% if not unlocked %}app--hidden{% endif %}">
|
|
|
|
|
| <aside class="sidebar">
|
| <div class="sidebar__brand">
|
| <div class="sidebar__mark">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
| <rect x="3" y="4" width="18" height="6" rx="1.5"/>
|
| <rect x="3" y="14" width="18" height="6" rx="1.5"/>
|
| <circle cx="7" cy="7" r=".8" fill="currentColor"/>
|
| <circle cx="7" cy="17" r=".8" fill="currentColor"/>
|
| </svg>
|
| </div>
|
| <div class="sidebar__name">
|
| <div class="sidebar__title">ServerClass</div>
|
| <div class="sidebar__subtitle mono">ADMIN · v2</div>
|
| </div>
|
| </div>
|
|
|
| <nav class="sidebar__nav">
|
| <button class="nav-item active" data-view="overview">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <rect x="3" y="3" width="7" height="9" rx="1.5"/>
|
| <rect x="14" y="3" width="7" height="5" rx="1.5"/>
|
| <rect x="14" y="12" width="7" height="9" rx="1.5"/>
|
| <rect x="3" y="16" width="7" height="5" rx="1.5"/>
|
| </svg>
|
| <span>Overview</span>
|
| </button>
|
| <button class="nav-item" data-view="servers">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <rect x="3" y="4" width="18" height="6" rx="1.5"/>
|
| <rect x="3" y="14" width="18" height="6" rx="1.5"/>
|
| <circle cx="7" cy="7" r=".8" fill="currentColor"/>
|
| <circle cx="7" cy="17" r=".8" fill="currentColor"/>
|
| </svg>
|
| <span>Servers</span>
|
| <span class="nav-item__count" id="navServersCount">—</span>
|
| </button>
|
| <button class="nav-item" data-view="users">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
|
| <circle cx="9" cy="7" r="4"/>
|
| <path d="M22 21v-2a4 4 0 0 0-3-3.87"/>
|
| <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
| </svg>
|
| <span>Users</span>
|
| <span class="nav-item__count" id="navUsersCount">—</span>
|
| </button>
|
| <button class="nav-item" data-view="settings">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <circle cx="12" cy="12" r="3"/>
|
| <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
| </svg>
|
| <span>Settings</span>
|
| </button>
|
| </nav>
|
|
|
| <div class="sidebar__footer">
|
| <div class="conn-pill" id="connPill" data-state="off">
|
| <span class="conn-pill__dot"></span>
|
| <span class="conn-pill__label" id="connLabel">Connecting</span>
|
| </div>
|
| <button class="sidebar__logout" id="lockBtn" title="Lock dashboard">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/>
|
| <path d="M16 17l5-5-5-5"/>
|
| <path d="M21 12H9"/>
|
| </svg>
|
| </button>
|
| </div>
|
| </aside>
|
|
|
|
|
| <main class="main">
|
|
|
|
|
| <header class="topbar">
|
| <div class="topbar__left">
|
| <div class="topbar__brand">
|
| <div class="topbar__mark">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
| <rect x="3" y="4" width="18" height="6" rx="1.5"/>
|
| <rect x="3" y="14" width="18" height="6" rx="1.5"/>
|
| </svg>
|
| </div>
|
| <div>
|
| <div class="topbar__title" id="topbarTitle">Overview</div>
|
| <div class="topbar__sub mono">
|
| <span class="conn-pill conn-pill--mini" id="connPillMini" data-state="off">
|
| <span class="conn-pill__dot"></span>
|
| <span id="connLabelMini">…</span>
|
| </span>
|
| · <span id="lastSync">—</span>
|
| </div>
|
| </div>
|
| </div>
|
| </div>
|
| <div class="topbar__right">
|
| <button class="icon-btn" id="refreshBtn" title="Refresh">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <path d="M3 12a9 9 0 0 1 15-6.7L21 8"/>
|
| <path d="M21 3v5h-5"/>
|
| <path d="M21 12a9 9 0 0 1-15 6.7L3 16"/>
|
| <path d="M3 21v-5h5"/>
|
| </svg>
|
| </button>
|
| <button class="icon-btn icon-btn--mobile" id="lockBtnMobile" title="Lock">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <rect x="3" y="11" width="18" height="11" rx="2"/>
|
| <path d="M7 11V7a5 5 0 0 1 10 0v4"/>
|
| </svg>
|
| </button>
|
| </div>
|
| </header>
|
|
|
|
|
| <div id="errorBox" class="error-stack"></div>
|
|
|
|
|
| <section class="view view--active" data-view="overview">
|
|
|
| <div class="view__head">
|
| <div>
|
| <div class="eyebrow mono">DASHBOARD</div>
|
| <h1 class="view__title">Overview</h1>
|
| <p class="view__sub">Real-time snapshot of your distributed authentication mesh.</p>
|
| </div>
|
| <div class="view__head-meta">
|
| <div class="live-indicator">
|
| <span class="live-indicator__pulse"></span>
|
| <span class="mono">LIVE</span>
|
| </div>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="kpi-grid" id="kpiGrid">
|
| <div class="kpi kpi--accent">
|
| <div class="kpi__icon">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
|
| <circle cx="9" cy="7" r="4"/>
|
| <path d="M22 21v-2a4 4 0 0 0-3-3.87"/>
|
| <path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
| </svg>
|
| </div>
|
| <div class="kpi__label mono">TOTAL USERS</div>
|
| <div class="kpi__value" id="kpiTotalUsers">—</div>
|
| <div class="kpi__trend mono"><span id="kpiTotalUsersSub">Registered accounts</span></div>
|
| </div>
|
|
|
| <div class="kpi">
|
| <div class="kpi__icon">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <rect x="3" y="4" width="18" height="6" rx="1.5"/>
|
| <rect x="3" y="14" width="18" height="6" rx="1.5"/>
|
| <circle cx="7" cy="7" r=".8" fill="currentColor"/>
|
| <circle cx="7" cy="17" r=".8" fill="currentColor"/>
|
| </svg>
|
| </div>
|
| <div class="kpi__label mono">SERVERS</div>
|
| <div class="kpi__value" id="kpiServers">—</div>
|
| <div class="kpi__trend mono"><span id="kpiServersSub">Online nodes</span></div>
|
| </div>
|
|
|
| <div class="kpi">
|
| <div class="kpi__icon">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <path d="M12 8v4l3 3"/>
|
| <circle cx="12" cy="12" r="10"/>
|
| </svg>
|
| </div>
|
| <div class="kpi__label mono">RESERVATIONS</div>
|
| <div class="kpi__value" id="kpiReservations">—</div>
|
| <div class="kpi__trend mono"><span id="kpiReservationsSub">Pending registrations</span></div>
|
| </div>
|
|
|
| <div class="kpi">
|
| <div class="kpi__icon">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <path d="M22 12h-4l-3 9L9 3l-3 9H2"/>
|
| </svg>
|
| </div>
|
| <div class="kpi__label mono">CAPACITY</div>
|
| <div class="kpi__value" id="kpiCapacity">—<span class="kpi__value-suffix">%</span></div>
|
| <div class="kpi__bar">
|
| <div class="kpi__bar-fill" id="kpiCapacityBar" style="width:0%"></div>
|
| </div>
|
| <div class="kpi__trend mono"><span id="kpiCapacitySub">— / —</span></div>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="card card--chart">
|
| <div class="card__head">
|
| <div>
|
| <div class="card__eyebrow mono">DISTRIBUTION</div>
|
| <h2 class="card__title">Server Load</h2>
|
| </div>
|
| <div class="card__legend">
|
| <span class="legend"><i class="legend__sw legend__sw--ok"></i>Healthy</span>
|
| <span class="legend"><i class="legend__sw legend__sw--warn"></i>High</span>
|
| <span class="legend"><i class="legend__sw legend__sw--full"></i>Full</span>
|
| </div>
|
| </div>
|
| <div class="chart" id="loadChart">
|
| <div class="chart__empty mono">Awaiting data…</div>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="split">
|
| <div class="card">
|
| <div class="card__head">
|
| <div>
|
| <div class="card__eyebrow mono">RECENT</div>
|
| <h2 class="card__title">Latest Users</h2>
|
| </div>
|
| <button class="link-btn" data-jump="users">View all →</button>
|
| </div>
|
| <div id="recentUsers" class="recent">
|
| <div class="recent__empty mono">No users yet.</div>
|
| </div>
|
| </div>
|
|
|
| <div class="card">
|
| <div class="card__head">
|
| <div>
|
| <div class="card__eyebrow mono">TOP LOAD</div>
|
| <h2 class="card__title">Busiest Servers</h2>
|
| </div>
|
| <button class="link-btn" data-jump="servers">View all →</button>
|
| </div>
|
| <div id="topServers" class="recent">
|
| <div class="recent__empty mono">No data yet.</div>
|
| </div>
|
| </div>
|
| </div>
|
|
|
| </section>
|
|
|
|
|
| <section class="view" data-view="servers">
|
| <div class="view__head">
|
| <div>
|
| <div class="eyebrow mono">INFRASTRUCTURE</div>
|
| <h1 class="view__title">Servers</h1>
|
| <p class="view__sub">Live capacity and health across every node.</p>
|
| </div>
|
| </div>
|
|
|
| <div class="toolbar">
|
| <div class="search">
|
| <svg class="search__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <circle cx="11" cy="11" r="8"/>
|
| <path d="m21 21-4.35-4.35"/>
|
| </svg>
|
| <input type="text" id="serverSearch" class="search__input" placeholder="Filter servers by number, URL, or status…">
|
| <span class="search__hint mono" id="serverCount">— nodes</span>
|
| </div>
|
| <div class="seg" id="serverFilter">
|
| <button data-filter="all" class="seg__btn active">All</button>
|
| <button data-filter="open" class="seg__btn">Open</button>
|
| <button data-filter="full" class="seg__btn">Full</button>
|
| </div>
|
| </div>
|
|
|
| <div id="serversContent" class="cards-grid">
|
| <div class="empty mono">Loading servers…</div>
|
| </div>
|
| </section>
|
|
|
|
|
| <section class="view" data-view="users">
|
| <div class="view__head">
|
| <div>
|
| <div class="eyebrow mono">DIRECTORY</div>
|
| <h1 class="view__title">Users</h1>
|
| <p class="view__sub">Every account, every token, every login.</p>
|
| </div>
|
| </div>
|
|
|
| <div class="toolbar">
|
| <div class="search">
|
| <svg class="search__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <circle cx="11" cy="11" r="8"/>
|
| <path d="m21 21-4.35-4.35"/>
|
| </svg>
|
| <input type="text" id="userSearch" class="search__input" placeholder="Search username, telegram ID, server…">
|
| <span class="search__hint mono" id="userCount">— records</span>
|
| </div>
|
| <button class="btn btn--ghost" id="exportBtn">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="16" height="16">
|
| <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
|
| <polyline points="7 10 12 15 17 10"/>
|
| <line x1="12" y1="15" x2="12" y2="3"/>
|
| </svg>
|
| Export CSV
|
| </button>
|
| </div>
|
|
|
| <div id="usersContent" class="users-wrap">
|
| <div class="empty mono">Loading users…</div>
|
| </div>
|
| </section>
|
|
|
|
|
| <section class="view" data-view="settings">
|
| <div class="view__head">
|
| <div>
|
| <div class="eyebrow mono">CONFIGURATION</div>
|
| <h1 class="view__title">Settings</h1>
|
| <p class="view__sub">Session and connection preferences.</p>
|
| </div>
|
| </div>
|
|
|
| <div class="settings">
|
| <div class="setting">
|
| <div>
|
| <div class="setting__label">Auto-refresh interval</div>
|
| <div class="setting__hint">How often the dashboard pulls fresh data from upstream.</div>
|
| </div>
|
| <div class="setting__value mono"><span id="pollInterval">{{ poll_interval }}</span>s</div>
|
| </div>
|
|
|
| <div class="setting">
|
| <div>
|
| <div class="setting__label">Upstream API</div>
|
| <div class="setting__hint">The backing ServerClass DB instance.</div>
|
| </div>
|
| <div class="setting__value mono">dooratre-db.hf.space</div>
|
| </div>
|
|
|
| <div class="setting">
|
| <div>
|
| <div class="setting__label">Session</div>
|
| <div class="setting__hint">You stay signed in for 30 days on this device.</div>
|
| </div>
|
| <div class="setting__value">
|
| <button class="btn btn--danger" id="lockBtnSettings">Lock dashboard</button>
|
| </div>
|
| </div>
|
|
|
| <div class="setting">
|
| <div>
|
| <div class="setting__label">Build</div>
|
| <div class="setting__hint">ServerClass Admin Console</div>
|
| </div>
|
| <div class="setting__value mono">v2.0 · MMXXV</div>
|
| </div>
|
| </div>
|
| </section>
|
|
|
| </main>
|
|
|
|
|
| <nav class="bottomnav">
|
| <button class="bottomnav__item active" data-view="overview">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <rect x="3" y="3" width="7" height="9" rx="1.5"/>
|
| <rect x="14" y="3" width="7" height="5" rx="1.5"/>
|
| <rect x="14" y="12" width="7" height="9" rx="1.5"/>
|
| <rect x="3" y="16" width="7" height="5" rx="1.5"/>
|
| </svg>
|
| <span>Overview</span>
|
| </button>
|
| <button class="bottomnav__item" data-view="servers">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <rect x="3" y="4" width="18" height="6" rx="1.5"/>
|
| <rect x="3" y="14" width="18" height="6" rx="1.5"/>
|
| <circle cx="7" cy="7" r=".8" fill="currentColor"/>
|
| <circle cx="7" cy="17" r=".8" fill="currentColor"/>
|
| </svg>
|
| <span>Servers</span>
|
| </button>
|
| <button class="bottomnav__item" data-view="users">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <path d="M16 21v-2a4a4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/>
|
| <circle cx="9" cy="7" r="4"/>
|
| </svg>
|
| <span>Users</span>
|
| </button>
|
| <button class="bottomnav__item" data-view="settings">
|
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
| <circle cx="12" cy="12" r="3"/>
|
| <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
| </svg>
|
| <span>Settings</span>
|
| </button>
|
| </nav>
|
|
|
| </div>
|
|
|
|
|
| <div id="toasts" class="toasts" aria-live="polite"></div>
|
|
|
| <script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
|
| <script>
|
| window.__POLL_INTERVAL__ = {{ poll_interval }};
|
| window.__UNLOCKED__ = {{ 'true' if unlocked else 'false' }};
|
| </script>
|
| <script src="{{ url_for('static', filename='js/dashboard.js') }}"></script>
|
| </body>
|
| </html> |