feat(ui): Provision-Wizard neu gestaltet
This commit is contained in:
parent
10a495c13c
commit
41e12d1235
1 changed files with 67 additions and 88 deletions
|
|
@ -61,73 +61,68 @@ const loginTmpl = `<!DOCTYPE html>
|
||||||
</html>`
|
</html>`
|
||||||
|
|
||||||
const provisionTmpl = `<!DOCTYPE html>
|
const provisionTmpl = `<!DOCTYPE html>
|
||||||
<html lang="de" data-theme="light">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<meta name="color-scheme" content="light">
|
|
||||||
<title>Einrichten – {{.Screen.Name}}</title>
|
<title>Einrichten – {{.Screen.Name}}</title>
|
||||||
<link rel="stylesheet" href="/static/bulma.min.css">
|
<link rel="stylesheet" href="/static/bulma.min.css">
|
||||||
<style>
|
<style>
|
||||||
body { background: #f5f5f5; }
|
:root { --morz-red:#E30613; --morz-red-dark:#B8000F; --nav-bg:#1A1A2E; --bg:#F7F8FA; --surface:#FFFFFF; --shadow-sm:0 1px 4px rgba(0,0,0,.08); --radius:8px; --radius-btn:6px; }
|
||||||
pre { background: #1e1e1e; color: #d4d4d4; padding: 1rem; border-radius: 4px;
|
body { background:var(--bg); font-family:system-ui,-apple-system,"Segoe UI",sans-serif; }
|
||||||
overflow-x: auto; font-size: 0.9em; line-height: 1.5; }
|
.navbar { background:var(--nav-bg) !important; }
|
||||||
.step-number { background: var(--bulma-primary, hsl(229, 53%, 53%)); color: #fff; border-radius: 50%;
|
.navbar-item { color:rgba(255,255,255,.85) !important; }
|
||||||
width: 2rem; height: 2rem; display: inline-flex;
|
.navbar-item:hover { background:rgba(255,255,255,.08) !important; color:#fff !important; }
|
||||||
align-items: center; justify-content: center;
|
.morz-brand .accent { color:var(--morz-red); font-weight:800; }
|
||||||
font-weight: bold; margin-right: 0.5rem; flex-shrink: 0; }
|
.box { border-radius:var(--radius); box-shadow:var(--shadow-sm); }
|
||||||
.step { display: flex; align-items: flex-start; gap: 1rem; margin-bottom: 2rem; }
|
.step-num { width:2.25rem; height:2.25rem; border-radius:50%; background:var(--morz-red); color:#fff;
|
||||||
|
display:inline-flex; align-items:center; justify-content:center; font-weight:800;
|
||||||
|
font-size:.95rem; flex-shrink:0; }
|
||||||
|
.step-row { display:flex; gap:1.25rem; align-items:flex-start; }
|
||||||
.step-body { flex:1; }
|
.step-body { flex:1; }
|
||||||
.copy-btn { cursor: pointer; font-size: 0.75em; }
|
pre { background:#0f172a; color:#e2e8f0; padding:1rem 1.25rem; border-radius:6px; font-size:.85rem;
|
||||||
|
line-height:1.6; overflow-x:auto; margin:.75rem 0; }
|
||||||
|
code { background:#f1f5f9; color:#1e293b; padding:.1em .35em; border-radius:4px; font-size:.875em; }
|
||||||
|
.copy-btn { font-size:.75rem; cursor:pointer; border-radius:4px; }
|
||||||
|
.button.is-primary { background:var(--morz-red) !important; border-color:var(--morz-red) !important; border-radius:var(--radius-btn); }
|
||||||
|
.button.is-primary:hover { background:var(--morz-red-dark) !important; border-color:var(--morz-red-dark) !important; }
|
||||||
|
.success-banner { background:#f0fdf4; border:1px solid #bbf7d0; color:#166534; border-radius:var(--radius); padding:1rem 1.25rem; margin-bottom:1.5rem; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar is-dark">
|
<nav class="navbar" role="navigation">
|
||||||
<div class="navbar-brand">
|
<div class="navbar-brand">
|
||||||
<a class="navbar-item" href="/admin">← Admin</a>
|
<a class="navbar-item" href="/admin">← Admin</a>
|
||||||
<span class="navbar-item"><strong>Bildschirm einrichten: {{.Screen.Name}}</strong></span>
|
<span class="navbar-item morz-brand"><span class="accent">MORZ</span> Infoboard</span>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<section class="section pb-0 pt-3">
|
<section class="section">
|
||||||
<div class="container" style="max-width:860px">
|
<div class="container" style="max-width:820px">
|
||||||
<nav class="breadcrumb" aria-label="breadcrumb">
|
|
||||||
<ul>
|
|
||||||
<li><a href="/admin">Admin</a></li>
|
|
||||||
<li class="is-active"><a href="#" aria-current="page">Neuer Bildschirm</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="section pt-2">
|
<div class="success-banner">
|
||||||
<div class="container" style="max-width:860px">
|
<strong>✓ Screen «{{.Screen.Name}}» ({{.Screen.Slug}}) wurde angelegt.</strong><br>
|
||||||
|
Führe die folgenden Schritte aus, um den Bildschirm zu provisionieren.
|
||||||
<div class="notification is-success is-light">
|
|
||||||
<strong>✓ Screen «{{.Screen.Name}}» ({{.Screen.Slug}}) wurde im Backend angelegt.</strong><br>
|
|
||||||
Führe die folgenden Schritte auf deinem Ansible-Host aus, um den Bildschirm zu provisionieren.
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Schritt 1 -->
|
<div class="box mb-4">
|
||||||
<div class="box">
|
<div class="step-row">
|
||||||
<div class="step">
|
<span class="step-num">1</span>
|
||||||
<span class="step-number">1</span>
|
|
||||||
<div class="step-body">
|
<div class="step-body">
|
||||||
<p class="title is-6">Host zur Ansible-Inventardatei hinzufügen</p>
|
<p class="has-text-weight-semibold mb-2">Host zur Ansible-Inventardatei hinzufügen</p>
|
||||||
<p class="mb-3">Öffne <code>ansible/inventory.yml</code> und füge den Host unter <code>signage_players → hosts</code> ein:</p>
|
<p class="mb-2 has-text-grey is-size-7">Öffne <code>ansible/inventory.yml</code> und füge ein:</p>
|
||||||
<pre id="inv"> {{.Screen.Slug}}:</pre>
|
<pre id="inv"> {{.Screen.Slug}}:</pre>
|
||||||
<button class="button is-small is-light copy-btn mt-2" onclick="copy('inv')">📋 Kopieren</button>
|
<button class="button is-small is-light copy-btn" onclick="copyEl('inv',this)">📋 Kopieren</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Schritt 2 -->
|
<div class="box mb-4">
|
||||||
<div class="box">
|
<div class="step-row">
|
||||||
<div class="step">
|
<span class="step-num">2</span>
|
||||||
<span class="step-number">2</span>
|
|
||||||
<div class="step-body">
|
<div class="step-body">
|
||||||
<p class="title is-6">Host-Variablen anlegen</p>
|
<p class="has-text-weight-semibold mb-2">Host-Variablen anlegen</p>
|
||||||
<p class="mb-3">Erstelle die Datei <code>ansible/host_vars/{{.Screen.Slug}}/vars.yml</code> mit folgendem Inhalt:</p>
|
<p class="mb-2 has-text-grey is-size-7">Erstelle <code>ansible/host_vars/{{.Screen.Slug}}/vars.yml</code>:</p>
|
||||||
<pre id="hostvars">---
|
<pre id="hostvars">---
|
||||||
ansible_host: {{.IP}}
|
ansible_host: {{.IP}}
|
||||||
ansible_user: {{.SSHUser}}
|
ansible_user: {{.SSHUser}}
|
||||||
|
|
@ -135,53 +130,45 @@ screen_id: {{.Screen.Slug}}
|
||||||
screen_name: "{{.Screen.Name}}"
|
screen_name: "{{.Screen.Name}}"
|
||||||
screen_orientation: {{.Orientation}}</pre>
|
screen_orientation: {{.Orientation}}</pre>
|
||||||
<div class="buttons mt-2">
|
<div class="buttons mt-2">
|
||||||
<button id="copy-btn-hostvars" class="button is-small is-light copy-btn" onclick="copy('hostvars', 'copy-btn-hostvars')">📋 Kopieren</button>
|
<button class="button is-small is-light copy-btn" id="btn-hostvars" onclick="copyEl('hostvars','btn-hostvars')">📋 Kopieren</button>
|
||||||
<button class="button is-small is-light" onclick="downloadFile(document.getElementById('hostvars').innerText, 'vars.yml')">⬇ Als Datei herunterladen</button>
|
<button class="button is-small is-light" onclick="dlFile(document.getElementById('hostvars').innerText,'vars.yml')">⬇ Herunterladen</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="help mt-2">Tipp: <code>mkdir -p ansible/host_vars/{{.Screen.Slug}}</code></p>
|
<p class="help mt-1">Tipp: <code>mkdir -p ansible/host_vars/{{.Screen.Slug}}</code></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Schritt 3 -->
|
<div class="box mb-4">
|
||||||
<div class="box">
|
<div class="step-row">
|
||||||
<div class="step">
|
<span class="step-num">3</span>
|
||||||
<span class="step-number">3</span>
|
|
||||||
<div class="step-body">
|
<div class="step-body">
|
||||||
<p class="title is-6">SSH-Zugang sicherstellen</p>
|
<p class="has-text-weight-semibold mb-2">SSH-Zugang sicherstellen</p>
|
||||||
<p>Stelle sicher, dass dein SSH-Key auf dem Zielgerät hinterlegt ist:</p>
|
|
||||||
<pre id="sshcopy">ssh-copy-id {{.SSHUser}}@{{.IP}}</pre>
|
<pre id="sshcopy">ssh-copy-id {{.SSHUser}}@{{.IP}}</pre>
|
||||||
<button class="button is-small is-light copy-btn mt-2" onclick="copy('sshcopy')">📋 Kopieren</button>
|
<button class="button is-small is-light copy-btn" onclick="copyEl('sshcopy',this)">📋 Kopieren</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Schritt 4 -->
|
<div class="box mb-4">
|
||||||
<div class="box">
|
<div class="step-row">
|
||||||
<div class="step">
|
<span class="step-num">4</span>
|
||||||
<span class="step-number">4</span>
|
|
||||||
<div class="step-body">
|
<div class="step-body">
|
||||||
<p class="title is-6">Ansible-Playbook ausführen</p>
|
<p class="has-text-weight-semibold mb-2">Ansible-Playbook ausführen</p>
|
||||||
<p class="mb-3">Führe das Playbook vom Projektverzeichnis aus aus. Das installiert den Agent, konfiguriert Chromium und startet den Kiosk-Modus:</p>
|
<pre id="playcmd">cd /path/to/morz-infoboard
|
||||||
<pre id="playbookcmd">cd /path/to/morz-infoboard
|
|
||||||
ansible-playbook -i ansible/inventory.yml ansible/site.yml --limit {{.Screen.Slug}}</pre>
|
ansible-playbook -i ansible/inventory.yml ansible/site.yml --limit {{.Screen.Slug}}</pre>
|
||||||
<button class="button is-small is-light copy-btn mt-2" onclick="copy('playbookcmd')">📋 Kopieren</button>
|
<button class="button is-small is-light copy-btn" onclick="copyEl('playcmd',this)">📋 Kopieren</button>
|
||||||
<p class="help mt-2">
|
<p class="help mt-1">Mit Vault: <code>--vault-password-file ansible/.vault_pass</code></p>
|
||||||
Falls du einen Vault-Pass verwendest:
|
|
||||||
<code>--vault-password-file ansible/.vault_pass</code>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Schritt 5 -->
|
<div class="box" style="border-left:4px solid #22c55e">
|
||||||
<div class="box">
|
<div class="step-row">
|
||||||
<div class="step">
|
<span class="step-num" style="background:#22c55e">5</span>
|
||||||
<span class="step-number">5</span>
|
|
||||||
<div class="step-body">
|
<div class="step-body">
|
||||||
<p class="title is-6">Fertig — Playlist befüllen</p>
|
<p class="has-text-weight-semibold mb-2">Fertig — Playlist befüllen</p>
|
||||||
<p>Nach erfolgreichem Ansible-Lauf meldet sich der Bildschirm automatisch im Backend an und lädt seine Playlist. Jetzt kannst du Inhalte zuweisen:</p>
|
<p class="mb-3 has-text-grey">Nach dem Ansible-Lauf meldet sich der Bildschirm automatisch an.</p>
|
||||||
<div class="buttons mt-3">
|
<div class="buttons">
|
||||||
<a class="button is-primary" href="/manage/{{.Screen.Slug}}">Playlist für «{{.Screen.Name}}» verwalten →</a>
|
<a class="button is-primary" href="/manage/{{.Screen.Slug}}">Playlist für «{{.Screen.Name}}» verwalten →</a>
|
||||||
<a class="button" href="/admin">← Zurück zu Admin</a>
|
<a class="button" href="/admin">← Zurück zu Admin</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -191,27 +178,19 @@ ansible-playbook -i ansible/inventory.yml ansible/site.yml --limit {{.Screen.Slu
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function copy(id, btnId) {
|
function copyEl(id, btn) {
|
||||||
var el = document.getElementById(id);
|
navigator.clipboard.writeText(document.getElementById(id).innerText).then(function() {
|
||||||
if (!el) return;
|
var b = typeof btn === 'string' ? document.getElementById(btn) : btn;
|
||||||
navigator.clipboard.writeText(el.innerText).then(function() {
|
if (!b) return;
|
||||||
var btn = btnId
|
var orig = b.textContent; b.textContent = '✓ Kopiert!';
|
||||||
? document.getElementById(btnId)
|
setTimeout(function() { b.textContent = orig; }, 1500);
|
||||||
: el.nextElementSibling;
|
|
||||||
if (!btn) return;
|
|
||||||
var orig = btn.textContent;
|
|
||||||
btn.textContent = '✓ Kopiert!';
|
|
||||||
setTimeout(function() { btn.textContent = orig; }, 1500);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function dlFile(content, name) {
|
||||||
function downloadFile(content, filename) {
|
|
||||||
var a = document.createElement('a');
|
var a = document.createElement('a');
|
||||||
a.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(content);
|
a.href = 'data:text/plain;charset=utf-8,' + encodeURIComponent(content);
|
||||||
a.download = filename;
|
a.download = name; a.click();
|
||||||
a.click();
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue