This commit is contained in:
2025-08-10 12:43:48 +02:00
parent 5797ac22c8
commit d4b811dbad
31 changed files with 2004 additions and 172 deletions

View File

@@ -0,0 +1,350 @@
{% load static %}
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Einstellungen Subscribarr</title>
<style>
:root {
--bg: #0b0b10;
--panel: #12121a;
--panel-b: #1f2030;
--accent: #3b82f6;
--muted: #9aa0b4;
--text: #e6e6e6;
}
* {
box-sizing: border-box
}
body {
background: var(--bg);
color: var(--text);
font-family: system-ui, Segoe UI, Roboto, Arial, sans-serif;
margin: 0
}
.wrap {
max-width: 1000px;
margin: 0 auto;
padding: 16px
}
a {
color: #cfd3ea;
text-decoration: none
}
.topbar {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px
}
.btn {
padding: 10px 14px;
border-radius: 10px;
border: 1px solid #2a2a34;
background: #111119;
color: #fff;
cursor: pointer
}
.btn-primary {
background: var(--accent);
border-color: transparent
}
.grid {
display: grid;
gap: 16px
}
@media(min-width:900px) {
.grid {
grid-template-columns: 1fr 1fr
}
}
.card {
background: var(--panel);
border: 1px solid var(--panel-b);
border-radius: 12px;
padding: 14px
}
.card h2 {
margin: 0 0 10px;
font-size: 1.05rem
}
.row {
display: grid;
grid-template-columns: 160px minmax(0, 1fr);
/* <= statt 160px 1fr */
gap: 10px;
align-items: center;
margin-bottom: 10px;
}
.row label {
color: #c9cbe3
}
.row input,
.row select {
width: 100%;
padding: 10px 12px;
border-radius: 10px;
border: 1px solid #2a2a34;
background: #111119;
color: var(--text)
}
.help {
color: var(--muted);
font-size: .9rem
}
.msgs {
margin-bottom: 10px
}
.msg {
background: #0f1425;
border: 1px solid #283058;
border-radius: 10px;
padding: 10px;
margin-bottom: 8px
}
.input-wide {
width: 100% !important;
max-width: 100%;
min-width: 0;
display: block;
}
.row input,
.row select,
.row textarea {
width: 100%;
max-width: 100%;
min-width: 0;
display: block;
}
/* falls du passwort/URL Felder extra stylen willst, gleicher Fix */
.inline>input,
.inline>.django-url,
/* falls Widget eine Klasse rendert */
.inline>.django-password {
min-width: 0;
width: 100%;
}
.inline-actions {
display: inline-flex;
align-items: center;
gap: 8px;
min-width: 220px;
justify-content: flex-end;
}
.btn {
padding: 10px 14px;
border-radius: 10px;
border: 1px solid #2a2a34;
background: #111119;
color: #fff;
cursor: pointer;
}
.btn:disabled {
opacity: .6;
cursor: default;
}
.badge {
padding: 6px 10px;
border-radius: 999px;
font-size: .85rem;
border: 1px solid #2a2a34;
background: #111119;
color: #cfd3ea;
white-space: nowrap;
/* eine Zeile */
max-width: 140px;
/* begrenzt die Breite */
overflow: hidden;
text-overflow: ellipsis;
/* falls doch Text drin ist */
}
.badge.ok {
border-color: #1f6f3a;
background: #10331f;
color: #a7e3bd;
}
.badge.err {
border-color: #6f1f2a;
background: #341016;
color: #f1a3b0;
}
.badge.muted {
opacity: .8;
}
</style>
</head>
<body>
<div class="wrap">
<div class="topbar">
<div><a href="/" class="btn">← Zurück</a></div>
<div><strong>Einstellungen</strong></div>
<div></div>
</div>
{% if messages %}
<div class="msgs">{% for m in messages %}<div class="msg">{{ m }}</div>{% endfor %}</div>
{% endif %}
<form method="post">
{% csrf_token %}
<div class="grid">
<div class="card">
<h2>Sonarr & Radarr</h2>
<div class="row">
<label>Sonarr URL</label>
<div class="inline">
<div class="field">{{ arr_form.sonarr_url }}</div>
<div class="inline-actions">
<button class="btn" type="button" onclick="testConnection('sonarr', this)">Test
Sonarr</button>
<span id="sonarrStatus" class="badge muted"></span>
</div>
</div>
</div>
<div class="row">
<label>Sonarr API Key</label>
{{ arr_form.sonarr_api_key }}
</div>
<div class="row">
<label>Radarr URL</label>
<div class="inline">
<div class="field">{{ arr_form.radarr_url }}</div>
<div class="inline-actions">
<button class="btn" type="button" onclick="testConnection('radarr', this)">Test
Radarr</button>
<span id="radarrStatus" class="badge muted"></span>
</div>
</div>
</div>
<div class="row">
<label>Radarr API Key</label>
{{ arr_form.radarr_api_key }}
</div>
<div class="help">Klicke „Test …“, um die Verbindung gegen <code>/api/v3/system/status</code> zu
prüfen.</div>
</div>
<div class="card">
<h2>Mailserver</h2>
<div class="row"><label>Host</label>{{ mail_form.mail_host }}</div>
<div class="row"><label>Port</label>{{ mail_form.mail_port }}</div>
<div class="row"><label>Sicherheit</label>{{ mail_form.mail_secure }}</div>
<div class="row"><label>Benutzer</label>{{ mail_form.mail_user }}</div>
<div class="row"><label>Passwort</label>{{ mail_form.mail_password }}</div>
<div class="row"><label>Absender</label>{{ mail_form.mail_from }}</div>
</div>
<div class="card">
<h2>Konto</h2>
<div class="row"><label>Benutzername</label>{{ account_form.username }}</div>
<div class="row"><label>E-Mail</label>{{ account_form.email }}</div>
<div class="row"><label>Neues Passwort</label>{{ account_form.new_password }}</div>
<div class="row"><label>Passwort wiederholen</label>{{ account_form.repeat_password }}</div>
<div class="help">Nur Oberfläche Umsetzung Passwortänderung später.</div>
</div>
</div>
<div style="margin-top:16px">
<button class="btn btn-primary" type="submit">Speichern</button>
</div>
</form>
</div>
<script>
function testConnection(kind) {
const url = document.querySelector(`input[name="${kind}_url"]`).value;
const key = document.querySelector(`input[name="${kind}_api_key"]`).value;
fetch(`/settings/test-connection/?kind=${kind}&url=${encodeURIComponent(url)}&key=${encodeURIComponent(key)}`)
.then(r => r.json())
.then(data => {
if (data.ok) {
alert(kind + " Verbindung erfolgreich!");
} else {
alert(kind + " Fehler: " + data.error);
}
})
.catch(err => alert(kind + " Fehler: " + err));
}
function setBadge(kind, state, text, tooltip) {
const el = document.getElementById(kind + "Status");
if (!el) return;
el.classList.remove("ok", "err", "muted");
el.title = tooltip || ""; // voller Fehlertext im Tooltip
if (state === "ok") {
el.classList.add("ok");
el.textContent = "Verbunden";
} else if (state === "err") {
el.classList.add("err");
el.textContent = "Fehler";
} else {
el.classList.add("muted");
el.textContent = "—";
}
}
function testConnection(kind, btnEl) {
const urlEl = document.querySelector(`input[name="${kind}_url"]`);
const keyEl = document.querySelector(`input[name="${kind}_api_key"]`);
const url = urlEl ? urlEl.value.trim() : "";
const key = keyEl ? keyEl.value.trim() : "";
setBadge(kind, "muted", "Teste…");
if (btnEl) { btnEl.disabled = true; }
fetch(`/settings/test-connection/?kind=${encodeURIComponent(kind)}&url=${encodeURIComponent(url)}&key=${encodeURIComponent(key)}`)
.then(r => r.json())
.then(data => {
if (data.ok) {
setBadge(kind, "ok", "Verbunden", "");
} else {
setBadge(kind, "err", "Fehler", data.error || "Unbekannter Fehler");
}
})
.catch(err => setBadge(kind, "err", "Fehler", String(err)))
.finally(() => { if (btnEl) btnEl.disabled = false; });
}
</script>
</body>
</html>