www/templates/index.html
Sundog Garage Studio 411038582a Initial commit
2026-03-17 16:17:53 +02:00

209 lines
10 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RedUnits Control Panel</title>
<link rel="stylesheet" href="/static/css/style.css">
<!-- Alpine.js served locally (no CDN dependency) -->
<script defer src="/static/js/alpine.min.js"></script>
<script src="/static/js/marked.min.js"></script>
</head>
<body>
<div class="container" x-data="dashboard()" x-init="init()">
<!-- Toast notification -->
<div class="toast" x-show="actionMessage" x-transition :class="actionError ? 'toast-error' : 'toast-success'"
style="display: none;">
<span x-text="actionMessage"></span>
</div>
<header>
<div class="header-left">
<div class="logo-dot"></div>
<h1>RedUnits Control Panel</h1>
</div>
<div class="header-right">
<!-- Live WS indicator -->
<div class="indicator-group" :class="wsConnected ? 'ws-live' : 'ws-offline'">
<span class="ws-dot"></span>
<span x-text="wsConnected ? 'live' : 'reconnecting...'"></span>
</div>
<div class="last-update" x-text="lastUpdate"></div>
<button @click="refresh()" class="refresh-btn" :disabled="loading">
<span x-show="!loading">↻ refresh</span>
<span x-show="loading">⏳...</span>
</button>
</div>
</header>
<!-- SYSTEM STATUS SECTION -->
<section class="section">
<h2 class="section-title">SYSTEM STATUS</h2>
<div class="system-grid">
<div class="stat-card">
<div class="stat-label">CPU usage</div>
<div class="stat-value" x-text="system.cpu.percent + '%'"></div>
<div class="progress-bar">
<div class="progress-fill" :style="`width: ${system.cpu.percent}%`"
:class="getProgressColor(system.cpu.percent)"></div>
</div>
</div>
<div class="stat-card">
<div class="stat-label">Memory usage</div>
<div class="stat-value" x-text="system.memory.percent + '%'"></div>
<div class="progress-bar">
<div class="progress-fill" :style="`width: ${system.memory.percent}%`"
:class="getProgressColor(system.memory.percent)"></div>
</div>
<div class="stat-detail" x-text="`${system.memory.used_gb} GB / ${system.memory.total_gb} GB`">
</div>
</div>
<div class="stat-card">
<div class="stat-label">Docker containers</div>
<div class="stat-value" x-text="`${system.containers.running} / ${system.containers.total}`"></div>
<div class="progress-bar">
<div class="progress-fill"
:style="`width: ${system.containers.total > 0 ? (system.containers.running / system.containers.total * 100) : 0}%`"
:class="system.containers.running === system.containers.total ? 'green' : 'red'"></div>
</div>
<div class="stat-detail">
<span x-show="system.containers.running < system.containers.total"
x-text="`${system.containers.total - system.containers.running} container${(system.containers.total - system.containers.running) > 1 ? 's' : ''} offline`"></span>
<span x-show="system.containers.running === system.containers.total">All containers
running</span>
</div>
</div>
<div class="stat-card">
<div class="stat-label">System uptime</div>
<div class="stat-value" x-text="system.uptime.days + ' days'"></div>
<div class="stat-status" :class="allServicesOnline() ? 'status-ok' : 'status-warn'">
<span x-show="allServicesOnline()">✓ All services operational</span>
<span x-show="!allServicesOnline()" style="display: flex; align-items: center; gap: 6px;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"></circle>
<line x1="12" y1="8" x2="12" y2="12"></line>
<line x1="12" y1="16" x2="12.01" y2="16"></line>
</svg>
Some services offline
</span>
</div>
</div>
</div>
</section>
<!-- SERVICES SECTION -->
<section class="section">
<h2 class="section-title">SERVICES</h2>
<div class="services-grid">
<template x-for="service in services" :key="service.id">
<div class="service-card" :class="!service.status.online ? 'card-offline' : ''">
<div class="service-header">
<div class="service-name">
<span class="service-icon" x-text="service.icon"></span>
<span x-text="service.name"></span>
</div>
<div class="status-badge"
:class="service.status.online ? 'status-online' : 'status-offline'">
<span x-text="service.status.online ? 'online' : 'offline'"></span>
</div>
</div>
<div class="service-description" x-text="service.description"></div>
<div class="service-url" x-text="service.url"></div>
<!-- Online State Info -->
<template x-if="service.status.online">
<div class="service-metrics">
<div class="metric">
<span class="metric-label">CPU</span>
<span class="metric-value"><span x-text="service.status.cpu_percent"></span>%</span>
</div>
<div class="metric">
<span class="metric-label">RAM</span>
<span class="metric-value">
<span x-text="service.status.memory_mb"></span> <span
class="metric-unit">MB</span>
</span>
</div>
<div class="metric">
<span class="metric-label">Uptime</span>
<span class="metric-value" x-text="service.status.uptime"></span>
</div>
</div>
</template>
<!-- Offline State Info -->
<template x-if="!service.status.online">
<div class="offline-message">
Container is not running
</div>
</template>
<!-- Actions for Online -->
<div class="service-actions" x-show="service.status.online" style="display: none;">
<a :href="service.url" target="_blank" class="btn btn-primary">Open</a>
<button class="btn btn-icon" @click="restartService(service.id)" title="Restart container">
</button>
<button class="btn btn-outline" @click="stopService(service.id)" title="Stop container">
Stop
</button>
</div>
<!-- Actions for Offline -->
<div class="service-actions-center" x-show="!service.status.online" style="display: none;">
<button class="btn btn-outline btn-full" @click="restartService(service.id)">
↻ Restart service
</button>
</div>
</div>
</template>
</div>
</section>
<!-- DOCUMENTS SECTION -->
<section class="section" x-show="documents.length > 0" style="display: none;">
<h2 class="section-title">QUICK LINKS & DOCS</h2>
<div class="docs-list">
<template x-for="doc in documents" :key="doc.id">
<div class="doc-item" @click="openDocument(doc)">
<span class="doc-icon">📄</span>
<div class="doc-info">
<div class="doc-title" x-text="doc.title"></div>
<div class="doc-desc" x-text="doc.description"></div>
</div>
</div>
</template>
</div>
</section>
<!-- DOCUMENT MODAL -->
<div class="modal-overlay" x-show="showDocModal" style="display: none;">
<div class="modal-content" @click.away="closeDocument()">
<div class="modal-header">
<h3 x-text="docTitle"></h3>
<button class="modal-close" @click="closeDocument()"></button>
</div>
<div class="modal-body">
<div x-show="docLoading" class="doc-loading">⏳ Loading document...</div>
<div class="markdown-body" x-html="docContent" x-show="!docLoading"></div>
</div>
</div>
</div>
<footer>
<p>RedUnits Control Panel v1.3</p>
</footer>
</div>
<script src="/static/js/app.js"></script>
</body>
</html>