clupilot/templates/akutell/Cluster anlegen.html

339 lines
22 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>CluPilot — Cluster anlegen</title>
<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&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="clupilot.css">
<style>
.wizard{display:grid;grid-template-columns:1fr 320px;gap:18px;align-items:start}
.step-pane{display:none;animation:fade .25s ease}
.step-pane.active{display:block}
@keyframes fade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.summary{position:sticky;top:84px;display:flex;flex-direction:column;gap:0}
.sum-price{font-family:var(--mono);font-size:26px;font-weight:600;letter-spacing:-0.02em}
.sum-price .unit{font-size:13px;color:var(--muted-2);font-weight:500}
.slider-row{display:flex;align-items:center;gap:14px}
.slider-row input[type=range]{flex:1;accent-color:var(--accent);height:5px}
.node-val{font-family:var(--mono);font-weight:600;font-size:18px;min-width:24px;text-align:center}
.wizard-foot{display:flex;align-items:center;justify-content:space-between;margin-top:6px}
@media (max-width:1100px){.wizard{grid-template-columns:1fr}.summary{position:static}}
</style>
</head>
<body>
<div class="app">
<aside class="sidebar" data-screen-label="Sidebar">
<div class="brand"><div class="brand-mark" aria-hidden="true"></div><div class="brand-name">CluPilot<span>v2.4</span></div></div>
<button class="ws-switch" aria-label="Workspace wechseln">
<div class="ws-avatar">AC</div>
<div class="ws-meta"><div class="ws-name">Acme Cluster</div><div class="ws-plan">team · 14 user</div></div>
<svg class="ws-chev" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 9l4-4 4 4M8 15l4 4 4-4"/></svg>
</button>
<nav class="nav">
<a class="nav-item" href="CluPilot Dashboard Glass.html"><svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><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>Dashboard</span></a>
<a class="nav-item active" href="Server.html"><svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><rect x="3" y="4" width="18" height="7" rx="1.5"/><rect x="3" y="13" width="18" height="7" rx="1.5"/><circle cx="7" cy="7.5" r="0.7" fill="currentColor"/><circle cx="7" cy="16.5" r="0.7" fill="currentColor"/></svg><span>Server</span><span class="count">6</span></a>
<a class="nav-item" href="Sites.html"><svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18"/></svg><span>Sites</span><span class="count">87</span></a>
<a class="nav-item" href="Backups.html"><svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M21 12c0 5-9 9-9 9s-9-4-9-9V5l9-3 9 3v7z"/><path d="M9 11l2 2 4-4"/></svg><span>Backups</span></a>
<a class="nav-item" href="Sicherheit.html"><svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M12 3l8 4v5c0 5-3.5 8-8 9-4.5-1-8-4-8-9V7l8-4z"/></svg><span>Sicherheit</span><span class="count" style="color:var(--warning);background:var(--warning-soft);border-color:rgba(194,130,15,0.3)">3</span></a>
<div class="nav-title">Konto</div>
<a class="nav-item" href="Team.html"><svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><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.9M16 3.1a4 4 0 0 1 0 7.8"/></svg><span>Team</span></a>
<a class="nav-item" href="Einstellungen.html"><svg class="ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1A1.7 1.7 0 0 0 4.6 9a1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/></svg><span>Einstellungen</span></a>
</nav>
<div class="plan-box">
<div class="plan-row"><div class="plan-name">Team Plan</div><div class="plan-tag">PRO</div></div>
<div class="plan-meter"><span></span></div>
<div class="plan-stats"><span>87 / 140 sites</span><span>62%</span></div>
</div>
</aside>
<main class="main" data-screen-label="Cluster anlegen">
<div class="topbar">
<a class="icon-btn" href="Server.html" aria-label="Zurück">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M15 18l-6-6 6-6"/></svg>
</a>
<div>
<div class="page-title">Cluster anlegen</div>
<div class="page-sub">neuer server-cluster · acme</div>
</div>
<div class="top-spacer"></div>
<div class="stepper" id="stepper">
<div class="step active" data-step="0"><span class="num">1</span>Basis</div>
<span class="step-line"></span>
<div class="step" data-step="1"><span class="num">2</span>Region &amp; Hardware</div>
<span class="step-line"></span>
<div class="step" data-step="2"><span class="num">3</span>WordPress</div>
<span class="step-line"></span>
<div class="step" data-step="3"><span class="num">4</span>Überprüfen</div>
</div>
</div>
<div class="content">
<div class="wizard">
<!-- ============ FORM ============ -->
<div>
<!-- STEP 1 -->
<div class="step-pane active" data-pane="0">
<section class="card">
<div class="card-head"><h3>Basis-Konfiguration</h3><span class="meta">schritt 1 / 4</span></div>
<div class="card-body">
<div class="field">
<label>Cluster-Name</label>
<input class="input" id="f-name" value="eu-prod-04" placeholder="z. B. eu-prod-04" />
<span class="hint">Wird in Listen, SSH und im Audit-Log angezeigt.</span>
</div>
<div class="field">
<label>Slug / Hostname</label>
<div class="input-group"><input id="f-slug" value="eu-prod-04" /><span class="suffix">.clupilot.net</span></div>
</div>
<div class="field">
<label>Umgebung</label>
<div class="opt-grid cols-3" data-radio="env">
<div class="opt selected" data-val="Produktion"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">Produktion</div><div class="opt-desc">live · monitoring</div></div></div>
<div class="opt" data-val="Staging"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">Staging</div><div class="opt-desc">test · isoliert</div></div></div>
<div class="opt" data-val="Entwicklung"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">Entwicklung</div><div class="opt-desc">sandbox</div></div></div>
</div>
</div>
<div class="field">
<label>Beschreibung <span class="hint" style="font-weight:400">(optional)</span></label>
<textarea class="input" id="f-desc" placeholder="Wofür ist dieser Cluster gedacht?"></textarea>
</div>
</div>
</section>
</div>
<!-- STEP 2 -->
<div class="step-pane" data-pane="1">
<section class="card">
<div class="card-head"><h3>Region</h3><span class="meta">schritt 2 / 4</span></div>
<div class="card-body">
<div class="opt-grid cols-2" data-radio="region">
<div class="opt selected" data-val="Frankfurt · de-fra"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">🇩🇪 Frankfurt</div><div class="opt-desc">de-fra · 4 ms</div></div></div>
<div class="opt" data-val="Amsterdam · nl-ams"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">🇳🇱 Amsterdam</div><div class="opt-desc">nl-ams · 11 ms</div></div></div>
<div class="opt" data-val="Helsinki · fi-hel"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">🇫🇮 Helsinki</div><div class="opt-desc">fi-hel · 24 ms</div></div></div>
<div class="opt" data-val="Ashburn · us-east"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">🇺🇸 Ashburn</div><div class="opt-desc">us-east · 92 ms</div></div></div>
</div>
</div>
</section>
<section class="card" style="margin-top:18px">
<div class="card-head"><h3>Server-Größe</h3></div>
<div class="card-body">
<div class="opt-grid" data-radio="size" data-price>
<div class="opt" data-val="Starter" data-amt="29"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">Starter</div><div class="opt-desc">2 vCPU · 8 GB · 160 GB NVMe · ~15 sites</div></div><div class="opt-price">29 €/mo</div></div>
<div class="opt selected" data-val="Standard" data-amt="59"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">Standard <span class="pill accent" style="margin-left:4px">beliebt</span></div><div class="opt-desc">4 vCPU · 16 GB · 320 GB NVMe · ~40 sites</div></div><div class="opt-price">59 €/mo</div></div>
<div class="opt" data-val="Performance" data-amt="119"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">Performance</div><div class="opt-desc">8 vCPU · 32 GB · 640 GB NVMe · ~90 sites</div></div><div class="opt-price">119 €/mo</div></div>
<div class="opt" data-val="Dedicated" data-amt="249"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">Dedicated</div><div class="opt-desc">16 vCPU · 64 GB · 1,2 TB NVMe · ~200 sites</div></div><div class="opt-price">249 €/mo</div></div>
</div>
<div class="field" style="margin-top:18px;margin-bottom:0">
<label>Anzahl Nodes</label>
<div class="slider-row">
<input type="range" id="f-nodes" min="1" max="6" value="1" />
<span class="node-val" id="nodes-val">1</span>
</div>
<span class="hint">Ab 2 Nodes wird automatisch ein Load-Balancer & Failover eingerichtet.</span>
</div>
</div>
</section>
</div>
<!-- STEP 3 -->
<div class="step-pane" data-pane="2">
<section class="card">
<div class="card-head"><h3>WordPress-Voreinstellungen</h3><span class="meta">schritt 3 / 4</span></div>
<div class="card-body">
<div class="grid-2">
<div class="field"><label>PHP-Version</label>
<div class="opt-grid cols-3" data-radio="php">
<div class="opt" data-val="8.1"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">8.1</div></div></div>
<div class="opt selected" data-val="8.2"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">8.2</div></div></div>
<div class="opt" data-val="8.3"><span class="opt-radio"></span><div class="opt-main"><div class="opt-title">8.3</div></div></div>
</div>
</div>
<div class="field"><label>WordPress-Version</label><input class="input input-mono" value="6.5.2 (aktuell)" readonly /></div>
</div>
<div style="margin-top:6px">
<div class="toggle-row" data-toggle="autoupdate"><div class="tr-body"><div class="tr-title">Automatische Updates</div><div class="tr-desc">core- & sichere plugin-updates</div></div><div class="toggle on"></div></div>
<div class="toggle-row" data-toggle="ssl"><div class="tr-body"><div class="tr-title">SSL automatisch (Let's Encrypt)</div><div class="tr-desc">zertifikate ausstellen & erneuern</div></div><div class="toggle on"></div></div>
<div class="toggle-row" data-toggle="cdn"><div class="tr-body"><div class="tr-title">Edge-CDN & Cache</div><div class="tr-desc">globaler cache für statische inhalte</div></div><div class="toggle on"></div></div>
<div class="toggle-row" data-toggle="backup"><div class="tr-body"><div class="tr-title">Tägliche Backups</div><div class="tr-desc">03:00 utc · 30 tage aufbewahrung</div></div><div class="toggle on"></div></div>
<div class="toggle-row" data-toggle="waf"><div class="tr-body"><div class="tr-title">WAF & Brute-Force-Schutz</div><div class="tr-desc">managed firewall-regelsatz</div></div><div class="toggle on"></div></div>
</div>
</div>
</section>
</div>
<!-- STEP 4 -->
<div class="step-pane" data-pane="3">
<section class="card">
<div class="card-head"><h3><svg class="hico" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 12l5 5L20 7"/></svg>Überprüfen &amp; anlegen</h3><span class="meta">schritt 4 / 4</span></div>
<div class="card-body">
<div class="kv"><span class="k">Cluster-Name</span><span class="v" data-review="name">eu-prod-04</span></div>
<div class="kv"><span class="k">Hostname</span><span class="v" data-review="host">eu-prod-04.clupilot.net</span></div>
<div class="kv"><span class="k">Umgebung</span><span class="v" data-review="env">Produktion</span></div>
<div class="kv"><span class="k">Region</span><span class="v" data-review="region">Frankfurt · de-fra</span></div>
<div class="kv"><span class="k">Server-Größe</span><span class="v" data-review="size">Standard</span></div>
<div class="kv"><span class="k">Nodes</span><span class="v" data-review="nodes">1</span></div>
<div class="kv"><span class="k">PHP / WordPress</span><span class="v" data-review="stack">8.2 · WP 6.5.2</span></div>
<div class="kv"><span class="k">Funktionen</span><span class="v" data-review="features">5 aktiv</span></div>
</div>
<div class="card-body" style="border-top:1px solid var(--hairline);display:flex;align-items:center;gap:12px">
<div class="feed-ico accent" style="width:34px;height:34px"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 8v5M12 16h.01"/><circle cx="12" cy="12" r="9"/></svg></div>
<div class="tr-desc" style="flex:1">Die Bereitstellung dauert i. d. R. <b>24 Minuten</b>. Du wirst benachrichtigt, sobald der Cluster bereit ist.</div>
</div>
</section>
</div>
<!-- nav buttons -->
<div class="wizard-foot">
<button class="btn-ghost" id="btn-back" style="visibility:hidden">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M15 18l-6-6 6-6"/></svg>Zurück
</button>
<button class="btn-primary lg" id="btn-next">
Weiter
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M9 6l6 6-6 6"/></svg>
</button>
</div>
</div>
<!-- ============ SUMMARY ============ -->
<section class="card summary">
<div class="card-head"><h3>Zusammenfassung</h3></div>
<div class="card-body">
<div class="kv"><span class="k">Name</span><span class="v" id="s-name">eu-prod-04</span></div>
<div class="kv"><span class="k">Umgebung</span><span class="v" id="s-env">Produktion</span></div>
<div class="kv"><span class="k">Region</span><span class="v" id="s-region">Frankfurt</span></div>
<div class="kv"><span class="k">Größe</span><span class="v" id="s-size">Standard</span></div>
<div class="kv"><span class="k">Nodes</span><span class="v" id="s-nodes">1×</span></div>
</div>
<div class="card-body" style="border-top:1px solid var(--hairline)">
<div style="display:flex;align-items:flex-end;justify-content:space-between">
<div>
<div class="tr-desc">Geschätzt / Monat</div>
<div class="sum-price"><span id="s-price">59</span><span class="unit">/mo</span></div>
</div>
<span class="pill success">inkl. backup</span>
</div>
<div class="hint" style="margin-top:10px">Abgerechnet pro Stunde · jederzeit kündbar. Preis exkl. MwSt.</div>
</div>
</section>
</div>
<div class="foot">CluPilot · bereitstellung über terraform · region eu-central-1</div>
</div>
</main>
</div>
<script>
const state = {
step:0, total:4,
name:'eu-prod-04', env:'Produktion', region:'Frankfurt · de-fra',
size:'Standard', amt:59, nodes:1, php:'8.2',
features:{autoupdate:true,ssl:true,cdn:true,backup:true,waf:true},
};
/* ---- radio option groups ---- */
document.querySelectorAll('[data-radio]').forEach(group=>{
group.querySelectorAll('.opt').forEach(opt=>{
opt.addEventListener('click',()=>{
group.querySelectorAll('.opt').forEach(o=>o.classList.remove('selected'));
opt.classList.add('selected');
const key = group.dataset.radio;
const val = opt.dataset.val;
if(key==='env') state.env = val;
if(key==='region') state.region = val;
if(key==='php') state.php = val;
if(key==='size'){ state.size = val; state.amt = +opt.dataset.amt; }
render();
});
});
});
/* ---- toggles ---- */
document.querySelectorAll('[data-toggle]').forEach(row=>{
const t = row.querySelector('.toggle');
row.addEventListener('click',()=>{
t.classList.toggle('on');
state.features[row.dataset.toggle] = t.classList.contains('on');
render();
});
});
/* ---- inputs ---- */
const nameEl = document.getElementById('f-name');
const slugEl = document.getElementById('f-slug');
nameEl.addEventListener('input',()=>{ state.name = nameEl.value || '—'; render(); });
const nodesEl = document.getElementById('f-nodes');
nodesEl.addEventListener('input',()=>{ state.nodes = +nodesEl.value; render(); });
/* ---- stepper ---- */
const panes = [...document.querySelectorAll('.step-pane')];
const steps = [...document.querySelectorAll('#stepper .step')];
const btnNext = document.getElementById('btn-next');
const btnBack = document.getElementById('btn-back');
function gotoStep(n){
state.step = Math.max(0, Math.min(state.total-1, n));
panes.forEach((p,i)=>p.classList.toggle('active', i===state.step));
steps.forEach((s,i)=>{
s.classList.toggle('active', i===state.step);
s.classList.toggle('done', i<state.step);
});
btnBack.style.visibility = state.step===0 ? 'hidden':'visible';
if(state.step===state.total-1){
btnNext.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M5 12l5 5L20 7"/></svg> Cluster anlegen';
}else{
btnNext.innerHTML = 'Weiter <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"><path d="M9 6l6 6-6 6"/></svg>';
}
render();
}
btnNext.addEventListener('click',()=>{
if(state.step===state.total-1){
btnNext.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" style="animation:spin 1s linear infinite"><path d="M21 12a9 9 0 1 1-6.2-8.5"/></svg> Wird angelegt…';
btnNext.disabled = true;
setTimeout(()=>{ window.location.href = 'Server.html'; }, 1400);
return;
}
gotoStep(state.step+1);
});
btnBack.addEventListener('click',()=>gotoStep(state.step-1));
steps.forEach(s=>s.addEventListener('click',()=>gotoStep(+s.dataset.step)));
/* ---- render derived values ---- */
function render(){
slugify();
const lb = state.nodes>1 ? state.nodes*state.amt + 9 : state.amt;
// summary card
document.getElementById('s-name').textContent = state.name;
document.getElementById('s-env').textContent = state.env;
document.getElementById('s-region').textContent = state.region.split(' · ')[0];
document.getElementById('s-size').textContent = state.size;
document.getElementById('s-nodes').textContent = state.nodes+'×';
document.getElementById('s-price').textContent = lb;
document.getElementById('nodes-val').textContent = state.nodes;
// review step
const feats = Object.values(state.features).filter(Boolean).length;
const set=(k,v)=>{const el=document.querySelector(`[data-review="${k}"]`); if(el) el.textContent=v;};
set('name', state.name);
set('host', (slugEl.value||state.name)+'.clupilot.net');
set('env', state.env);
set('region', state.region);
set('size', state.size+' · '+state.amt+' €/mo');
set('nodes', state.nodes + (state.nodes>1?' (+ load-balancer)':''));
set('stack', state.php+' · WP 6.5.2');
set('features', feats+' aktiv');
}
function slugify(){
if(document.activeElement!==slugEl){
slugEl.value = state.name.toLowerCase().replace(/[^a-z0-9-]+/g,'-').replace(/^-+|-+$/g,'');
}
}
const style=document.createElement('style');
style.textContent='@keyframes spin{to{transform:rotate(360deg)}}';
document.head.appendChild(style);
gotoStep(0);
</script>
</body>
</html>