[deploy] Fix dashboard icons and add missing register migration placeholder
All checks were successful
Deploy Discord Bot / deploy (push) Successful in 37s
All checks were successful
Deploy Discord Bot / deploy (push) Successful in 37s
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
-- Placeholder recreated because migration was already applied in the database.
|
||||
-- Schema changes are already present; this file keeps the migration timeline consistent.
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Placeholder recreated because this migration was applied in the database already.
|
||||
-- No schema changes required locally; keeps migration history aligned.
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Router } from 'express';
|
||||
import { Router } from 'express';
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -43,19 +43,19 @@ router.get('/', (req, res) => {
|
||||
<aside class="sidebar">
|
||||
<div class="brand">Papo Control</div>
|
||||
<div class="nav">
|
||||
<a class="active" href="#overview" data-target="overview"><span class="icon">ðŸ </span> Uebersicht</a>
|
||||
<a href="#tickets" data-target="tickets"><span class="icon">🎫</span> Ticketsystem</a>
|
||||
<a href="#automod" data-target="automod" class="automod-link"><span class="icon">🛡ï¸</span> Automod</a>
|
||||
<a href="#welcome" data-target="welcome" class="welcome-link"><span class="icon">✨</span> Willkommen</a>
|
||||
<a href="#dynamicvoice" data-target="dynamicvoice" class="dynamicvoice-link"><span class="icon">🎧</span> Dynamic Voice</a>
|
||||
<a href="#birthday" data-target="birthday" class="birthday-link"><span class="icon">🎂</span> Birthday</a>
|
||||
<a href="#reactionroles" data-target="reactionroles" class="reactionroles-link"><span class="icon">😎</span> Reaction Roles</a>
|
||||
<a href="#statuspage" data-target="statuspage" class="statuspage-link"><span class="icon">🖥ï¸</span> Statuspage</a>
|
||||
<a href="#serverstats" data-target="serverstats" class="serverstats-link"><span class="icon">??</span> Server Stats</a>
|
||||
<a href="#settings" data-target="settings"><span class="icon">âš™ï¸</span> Einstellungen</a>
|
||||
<a href="#modules" data-target="modules"><span class="icon">🧩</span> Module</a>
|
||||
<a href="#events" data-target="events" class="events-link"><span class="icon">📅</span> Events</a>
|
||||
<a href="#admin" data-target="admin" class="admin-link hidden"><span class="icon">🛡</span> Admin</a>
|
||||
<a class="active" href="#overview" data-target="overview"><span class="icon">🧭</span> Uebersicht</a>
|
||||
<a href="#tickets" data-target="tickets"><span class="icon">🎫</span> Ticketsystem</a>
|
||||
<a href="#automod" data-target="automod" class="automod-link"><span class="icon">🛡️</span> Automod</a>
|
||||
<a href="#welcome" data-target="welcome" class="welcome-link"><span class="icon">👋</span> Willkommen</a>
|
||||
<a href="#dynamicvoice" data-target="dynamicvoice" class="dynamicvoice-link"><span class="icon">🎧</span> Dynamic Voice</a>
|
||||
<a href="#birthday" data-target="birthday" class="birthday-link"><span class="icon">🎂</span> Birthday</a>
|
||||
<a href="#reactionroles" data-target="reactionroles" class="reactionroles-link"><span class="icon">🎭</span> Reaction Roles</a>
|
||||
<a href="#statuspage" data-target="statuspage" class="statuspage-link"><span class="icon">🖥️</span> Statuspage</a>
|
||||
<a href="#serverstats" data-target="serverstats" class="serverstats-link"><span class="icon">📈</span> Server Stats</a>
|
||||
<a href="#settings" data-target="settings"><span class="icon">⚙️</span> Einstellungen</a>
|
||||
<a href="#modules" data-target="modules"><span class="icon">🧩</span> Module</a>
|
||||
<a href="#events" data-target="events" class="events-link"><span class="icon">📅</span> Events</a>
|
||||
<a href="#admin" data-target="admin" class="admin-link hidden"><span class="icon">🛠️</span> Admin</a>
|
||||
</div>
|
||||
<div class="muted">Angemeldet als <span id="userInfo"></span></div>
|
||||
<button id="logoutBtn" class="logout">Logout</button>
|
||||
@@ -331,10 +331,10 @@ router.get('/', (req, res) => {
|
||||
<div class="card" style="display:flex; gap:10px; flex-wrap:wrap; align-items:center; justify-content:space-between;">
|
||||
<div>
|
||||
<p class="section-title">Tickets</p>
|
||||
<p class="section-sub">Übersicht, Pipeline, SLA, Automationen, Knowledge-Base.</p>
|
||||
<p class="section-sub">ÃÂÃÂbersicht, Pipeline, SLA, Automationen, Knowledge-Base.</p>
|
||||
</div>
|
||||
<div class="row" style="gap:8px; flex-wrap:wrap;">
|
||||
<button class="secondary-btn ticket-tab-btn active" data-tab="overview">Übersicht</button>
|
||||
<button class="secondary-btn ticket-tab-btn active" data-tab="overview">ÃÂÃÂbersicht</button>
|
||||
<button class="secondary-btn ticket-tab-btn" data-tab="pipeline">Pipeline</button>
|
||||
<button class="secondary-btn ticket-tab-btn" data-tab="sla">SLA</button>
|
||||
<button class="secondary-btn ticket-tab-btn" data-tab="automations">Automationen</button>
|
||||
@@ -347,7 +347,7 @@ router.get('/', (req, res) => {
|
||||
<div style="display:flex; align-items:center; justify-content:space-between; gap:12px;">
|
||||
<div>
|
||||
<p class="section-title">Ticketliste</p>
|
||||
<p class="section-sub">Links auswählen, Details im Modal. Plus öffnet Panel-Erstellung.</p>
|
||||
<p class="section-sub">Links auswÃÂählen, Details im Modal. Plus ÃÂöffnet Panel-Erstellung.</p>
|
||||
</div>
|
||||
<div class="row" style="gap:10px;">
|
||||
<button class="secondary-btn" id="openSupportLogin" type="button">Support-Login Einstellungen</button>
|
||||
@@ -382,7 +382,7 @@ router.get('/', (req, res) => {
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; gap:12px;">
|
||||
<div>
|
||||
<p class="section-title">Status-Pipeline</p>
|
||||
<p class="section-sub">Tickets nach Phase. Status per Dropdown ändern.</p>
|
||||
<p class="section-sub">Tickets nach Phase. Status per Dropdown ÃÂändern.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(240px,1fr)); gap:12px;" id="pipelineGrid">
|
||||
@@ -431,7 +431,7 @@ router.get('/', (req, res) => {
|
||||
<div style="display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap;">
|
||||
<div>
|
||||
<p class="section-title">Automationen</p>
|
||||
<p class="section-sub">Regeln für Ticket-Aktionen.</p>
|
||||
<p class="section-sub">Regeln fÃÂür Ticket-Aktionen.</p>
|
||||
</div>
|
||||
<button class="secondary-btn" id="addAutomation">Neue Regel</button>
|
||||
</div>
|
||||
@@ -468,7 +468,7 @@ router.get('/', (req, res) => {
|
||||
<div style="display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap;">
|
||||
<div>
|
||||
<p class="section-title">Knowledge-Base</p>
|
||||
<p class="section-sub">Artikel für Self-Service.</p>
|
||||
<p class="section-sub">Artikel fÃÂür Self-Service.</p>
|
||||
</div>
|
||||
<button class="secondary-btn" id="addKb">Neuer Artikel</button>
|
||||
</div>
|
||||
@@ -501,387 +501,13 @@ router.get('/', (req, res) => {
|
||||
</div>
|
||||
<form id="automodForm" style="margin-top:14px; display:flex; flex-direction:column; gap:12px;">
|
||||
<div class="option-grid">
|
||||
<div class="option-card">
|
||||
<label for="badWordFilter">Bad-Word-Filter</label>
|
||||
<div id="badWordFilter" class="switch"></div>
|
||||
</div>
|
||||
<div class="option-card">
|
||||
<label for="linkFilter">Link-/Invite-Filter</label>
|
||||
<div id="linkFilter" class="switch"></div>
|
||||
</div>
|
||||
<div class="option-card">
|
||||
<label for="spamFilter">Spam-/Flood-Erkennung</label>
|
||||
<div id="spamFilter" class="switch"></div>
|
||||
</div>
|
||||
<div class="option-card">
|
||||
<label for="capsFilter">Capslock-Filter</label>
|
||||
<div id="capsFilter" class="switch"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label class="form-label">Log Channel ID</label>
|
||||
<input id="automodLogChannel" placeholder="123456789012345678" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Empfindlichkeit</label>
|
||||
<select id="automodSensitivity">
|
||||
<option value="low">niedrig</option>
|
||||
<option value="medium">mittel</option>
|
||||
<option value="high">hoch</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label class="form-label">Whitelist-Links (kommagetrennt)</label>
|
||||
<input id="automodWhitelist" placeholder="example.com, partner.de" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label class="form-label">Custom Badwords (kommagetrennt oder zeilenweise)</label>
|
||||
<textarea id="automodBadwords" rows="3" placeholder="badword1, badword2"></textarea>
|
||||
<p class="muted">Diese Woerter werden zusaetzlich zum Standard-Filter geblockt.</p>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Whitelist-Rollen (IDs, Kommagetrennt)</label>
|
||||
<textarea id="automodWhitelistRoles" rows="3" placeholder="123,456"></textarea>
|
||||
<p class="muted">Nachrichten von diesen Rollen werden nicht gefiltert.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex; justify-content:flex-end; gap:10px;">
|
||||
<button type="submit">Speichern</button>
|
||||
</div>
|
||||
<p class="muted" id="automodStatus"></p>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
<div class="section" data-section="welcome">
|
||||
<section class="card">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; gap:12px; flex-wrap:wrap;">
|
||||
<div>
|
||||
<p class="section-title">Willkommensnachrichten</p>
|
||||
<p class="section-sub">Embed konfigurieren und Feature aktivieren.</p>
|
||||
</div>
|
||||
<div class="inline">
|
||||
<span class="form-label">Aktivieren</span>
|
||||
<div id="welcomeToggle" class="switch"></div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="welcomeForm" style="display:flex; flex-direction:column; gap:12px; margin-top:12px;">
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label class="form-label">Channel ID</label>
|
||||
<input id="welcomeChannel" placeholder="123456789012345678" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Embed-Farbe</label>
|
||||
<input id="welcomeColor" type="color" value="#f97316" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label class="form-label">Embed Titel</label>
|
||||
<input id="welcomeTitle" placeholder="Willkommen!" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Embed Footer</label>
|
||||
<input id="welcomeFooter" placeholder="Schön, dass du da bist!" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Embed Beschreibung</label>
|
||||
<textarea id="welcomeDescription" rows="3" placeholder="Du kannst {user} verwenden."></textarea>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label class="form-label">Thumbnail URL oder Upload</label>
|
||||
<input id="welcomeThumbnail" placeholder="https://..." />
|
||||
<input type="file" id="welcomeThumbnailFile" accept="image/*" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Bild URL oder Upload (GIFs erlaubt)</label>
|
||||
<input id="welcomeImage" placeholder="https://..." />
|
||||
<input type="file" id="welcomeImageFile" accept="image/*" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="embed-preview" id="welcomePreview">
|
||||
<div class="embed-color" id="welcomePreviewColor"></div>
|
||||
<div class="embed-body">
|
||||
<div class="embed-title" id="welcomePreviewTitle">Willkommen!</div>
|
||||
<div class="embed-desc" id="welcomePreviewDesc">Schön, dass du da bist.</div>
|
||||
<div class="embed-footer" id="welcomePreviewFooter">Footer</div>
|
||||
<img id="welcomePreviewImage" class="embed-image" style="display:none;" />
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex; justify-content:flex-end; gap:10px;">
|
||||
<button type="submit">Speichern</button>
|
||||
</div>
|
||||
<p class="muted" id="welcomeStatus"></p>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
<div class="section" data-section="dynamicvoice">
|
||||
<section class="card">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; gap:12px; flex-wrap:wrap;">
|
||||
<div>
|
||||
<p class="section-title">Dynamic Voice</p>
|
||||
<p class="section-sub">Lobby waehlen, Channel-Namen & Limits setzen.</p>
|
||||
</div>
|
||||
<div class="inline">
|
||||
<span class="form-label">Aktivieren</span>
|
||||
<div id="dynamicVoiceToggle" class="switch"></div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="dynamicVoiceForm" style="display:flex; flex-direction:column; gap:12px; margin-top:12px;">
|
||||
<div class="grid">
|
||||
<div class="form-field">
|
||||
<label class="form-label">Lobby Channel ID (Voice)</label>
|
||||
<input id="dynamicVoiceLobby" placeholder="123456789012345678" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Kategorie ID (optional)</label>
|
||||
<input id="dynamicVoiceCategory" placeholder="123456789012345678" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Name-Template</label>
|
||||
<input id="dynamicVoiceTemplate" placeholder="{user}s Channel" />
|
||||
<p class="muted">{user} wird durch den Mitgliedsnamen ersetzt.</p>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Userlimit (optional)</label>
|
||||
<input id="dynamicVoiceUserLimit" type="number" min="0" placeholder="0 = kein Limit" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Bitrate (optional)</label>
|
||||
<input id="dynamicVoiceBitrate" type="number" min="8000" placeholder="z.B. 64000" />
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex; justify-content:flex-end; gap:10px;">
|
||||
<button type="submit">Speichern</button>
|
||||
</div>
|
||||
<p class="muted" id="dynamicVoiceStatus"></p>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
<div class="section" data-section="modules">
|
||||
<section class="card">
|
||||
<p class="label">Module</p>
|
||||
<div id="moduleList" class="module-list"></div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="section" data-section="birthday">
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between; align-items:flex-start; gap:12px;">
|
||||
<div>
|
||||
<p class="section-title">Birthday</p>
|
||||
<p class="section-sub">Automatische Glueckwuensche je Guild.</p>
|
||||
</div>
|
||||
<div class="row" style="align-items:center; gap:10px; flex-wrap:wrap; justify-content:flex-end;">
|
||||
<label class="form-label">Sendezeit (Stunde)</label>
|
||||
<input id="birthdayHour" type="number" min="0" max="23" placeholder="9" style="width:80px;" />
|
||||
<label class="form-label">Channel ID</label>
|
||||
<input id="birthdayChannel" placeholder="123456789012345678" style="width:180px;" />
|
||||
<div id="birthdayToggle" class="switch"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Template</label>
|
||||
<textarea id="birthdayTemplate" rows="3" placeholder="Alles Gute zum Geburtstag, {user}!"></textarea>
|
||||
<p class="muted">Nutze {user} als Platzhalter.</p>
|
||||
</div>
|
||||
<div style="display:flex; justify-content:flex-end; gap:10px;">
|
||||
<button id="birthdaySave" type="button">Speichern</button>
|
||||
</div>
|
||||
<p class="muted" id="birthdayStatus"></p>
|
||||
</section>
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between; align-items:center;">
|
||||
<div>
|
||||
<p class="section-title">Gespeicherte Geburtstage</p>
|
||||
<p class="section-sub">Eintraege werden per /birthday angelegt.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="birthdayList" class="module-list"></div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="section" data-section="reactionroles">
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between; align-items:flex-start; gap:12px;">
|
||||
<div>
|
||||
<p class="section-title">Reaction Roles</p>
|
||||
<p class="section-sub">Reaktionen verteilen oder entfernen Rollen.</p>
|
||||
</div>
|
||||
<div class="muted" id="reactionRoleStatus"></div>
|
||||
</div>
|
||||
<form id="reactionRoleForm" style="display:flex; flex-direction:column; gap:12px; margin-top:8px;">
|
||||
<input type="hidden" id="reactionRoleId" />
|
||||
<div class="grid">
|
||||
<div class="form-field">
|
||||
<label class="form-label">Channel ID</label>
|
||||
<input id="reactionRoleChannel" placeholder="123456789012345678" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Message ID (optional)</label>
|
||||
<input id="reactionRoleMessageId" placeholder="Bestehende Nachricht verwenden" />
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Titel</label>
|
||||
<input id="reactionRoleTitle" placeholder="Rollenwahl" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Beschreibung</label>
|
||||
<textarea id="reactionRoleDescription" rows="2" placeholder="Kurze Beschreibung fuer das Embed"></textarea>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label class="form-label">Eintraege (Emoji | Role ID | Label | Beschreibung)</label>
|
||||
<textarea id="reactionRoleEntries" rows="4" placeholder="😀 | 123456789 | Freunde | Erhaelt Freunde Rolle"></textarea>
|
||||
<p class="muted">Eine Zeile pro Zuordnung. Label/Beschreibung optional.</p>
|
||||
</div>
|
||||
<div style="display:flex; justify-content:flex-end; gap:10px;">
|
||||
<button type="button" class="secondary-btn" id="reactionRoleReset">Reset</button>
|
||||
<button type="submit" id="reactionRoleSubmit">Speichern & senden</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between; align-items:center;">
|
||||
<div>
|
||||
<p class="section-title">Reaction Role Nachrichten</p>
|
||||
<p class="section-sub">Bestehende Setups bearbeiten oder syncen.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="reactionRoleList" class="module-list"></div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="section" data-section="statuspage">
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between;">
|
||||
<div>
|
||||
<p class="section-title">Statuspage</p>
|
||||
<p class="section-sub">Services verwalten und Checks steuern.</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="form-label">Intervall (ms)</label>
|
||||
<input id="statuspageInterval" type="number" min="30000" step="5000" placeholder="60000" />
|
||||
<label class="form-label">Channel ID</label>
|
||||
<input id="statuspageChannel" placeholder="Optional" />
|
||||
<div id="statuspageToggle" class="switch"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between;align-items:center;">
|
||||
<div>
|
||||
<p class="section-title">Services</p>
|
||||
<p class="section-sub">Status, Uptime, letzter Check</p>
|
||||
</div>
|
||||
<button class="icon-button" id="statuspageAddService">+</button>
|
||||
</div>
|
||||
<div id="statuspageServices" class="module-list"></div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="section" data-section="serverstats">
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between; align-items:center;">
|
||||
<div>
|
||||
<p class="section-title">Server Stats</p>
|
||||
<p class="section-sub">Erstellt eine Kategorie mit Voice-Statistiken.</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label class="form-label">Kategorie-Name</label>
|
||||
<input id="statsCategoryName" placeholder="?? Server Stats" />
|
||||
<label class="form-label">Refresh (Min)</label>
|
||||
<input id="statsRefresh" type="number" min="1" step="1" placeholder="10" />
|
||||
<div id="statsToggle" class="switch"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between; align-items:center;">
|
||||
<div>
|
||||
<p class="section-title">Statistiken</p>
|
||||
<p class="section-sub">Waehle Counter und Format.</p>
|
||||
</div>
|
||||
<button class="icon-button" id="statsAddItem">+</button>
|
||||
</div>
|
||||
<div id="statsItems" class="module-list"></div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="section" data-section="events">
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between; align-items:center;">
|
||||
<div>
|
||||
<p class="section-title">Events</p>
|
||||
<p class="section-sub">Termine planen und Erinnerungen senden.</p>
|
||||
</div>
|
||||
<button class="icon-button" id="openEventModal">+</button>
|
||||
</div>
|
||||
<div id="eventList" class="ticket-list-pane"></div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="section" data-section="admin">
|
||||
<div class="grid">
|
||||
<section class="card">
|
||||
<p class="section-title">Guilds</p>
|
||||
<p class="stat" id="adminGuilds">-</p>
|
||||
<p class="label">aktiv (24h): <span id="adminActiveGuilds">-</span></p>
|
||||
</section>
|
||||
<section class="card">
|
||||
<p class="section-title">Uptime</p>
|
||||
<p class="stat" id="adminUptime">-</p>
|
||||
<p class="label">Start: <span id="adminStart">-</span></p>
|
||||
</section>
|
||||
</div>
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between;">
|
||||
<div>
|
||||
<p class="section-title">Aktivität (letzte 24h)</p>
|
||||
<p class="section-sub">Events/Commands pro Stunde</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="activity-bars" id="adminActivity"></div>
|
||||
</section>
|
||||
<section class="card">
|
||||
<div class="row" style="justify-content:space-between;">
|
||||
<div>
|
||||
<p class="section-title">Logs</p>
|
||||
<p class="section-sub">Neueste Einträge</p>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="log-list" id="adminLogs"></ul>
|
||||
</section>
|
||||
</div>
|
||||
<div class="section" data-section="settings">
|
||||
<section class="card">
|
||||
<p class="label">Einstellungen speichern</p>
|
||||
<form id="settingsForm">
|
||||
<input name="welcomeChannelId" placeholder="Welcome Channel ID" />
|
||||
<input name="logChannelId" placeholder="Log Channel ID" />
|
||||
<input name="supportRoleId" placeholder="Support Role ID (optional)" />
|
||||
<button type="submit">Speichern</button>
|
||||
<p class="muted" id="saveStatus"></p>
|
||||
</form>
|
||||
</section>
|
||||
<section class="card">
|
||||
<p class="label">Logging</p>
|
||||
<div class="form-row">
|
||||
<div class="form-field">
|
||||
<label class="form-label">Log Channel ID (Logging)</label>
|
||||
<input id="loggingChannel" placeholder="123456789012345678" />
|
||||
<p class="muted">Falls leer, wird der allgemeine Log Channel genutzt.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="option-grid">
|
||||
<div class="option-card"><span>👋 User Join / Leave</span><div id="logJoinLeave" class="switch on"></div></div>
|
||||
<div class="option-card"><span>âœï¸ Message Edit</span><div id="logMsgEdit" class="switch on"></div></div>
|
||||
<div class="option-card"><span>ðŸ—‘ï¸ Message Delete</span><div id="logMsgDelete" class="switch on"></div></div>
|
||||
<div class="option-card"><span>ðŸ›¡ï¸ Automod Actions</span><div id="logAutomod" class="switch on"></div></div>
|
||||
<div class="option-card"><span>🎫 Ticket Actions</span><div id="logTickets" class="switch on"></div></div>
|
||||
<div class="option-card"><span>🎵 Musik-Events</span><div id="logMusic" class="switch on"></div></div>
|
||||
<div class="option-card"><span>âš™ï¸ System / Channels</span><div id="logSystem" class="switch on"></div></div>
|
||||
<div class="option-card"><span>👋 User Join / Leave</span><div id="logJoinLeave" class="switch on"></div></div>
|
||||
<div class="option-card"><span>✏️ Message Edit</span><div id="logMsgEdit" class="switch on"></div></div>
|
||||
<div class="option-card"><span>🗑️ Message Delete</span><div id="logMsgDelete" class="switch on"></div></div>
|
||||
<div class="option-card"><span>🛡️ Automod Actions</span><div id="logAutomod" class="switch on"></div></div>
|
||||
<div class="option-card"><span>🎫 Ticket Actions</span><div id="logTickets" class="switch on"></div></div>
|
||||
<div class="option-card"><span>🎵 Musik-Events</span><div id="logMusic" class="switch on"></div></div>
|
||||
<div class="option-card"><span>🛰️ System / Channels</span><div id="logSystem" class="switch on"></div></div>
|
||||
</div>
|
||||
<div style="display:flex; justify-content:flex-end; gap:10px; margin-top:12px;">
|
||||
<button id="loggingSave" type="button">Logging speichern</button>
|
||||
@@ -1439,7 +1065,7 @@ router.get('/', (req, res) => {
|
||||
const data = await res.json();
|
||||
serverStatsCache = data.config || { items: [] };
|
||||
setSwitch(statsToggle, serverStatsCache.enabled !== false);
|
||||
if (statsCategoryName) statsCategoryName.value = serverStatsCache.categoryName || '📊 Server Stats';
|
||||
if (statsCategoryName) statsCategoryName.value = serverStatsCache.categoryName || 'ðÃÂÃÂàServer Stats';
|
||||
if (statsRefresh) statsRefresh.value = serverStatsCache.refreshMinutes ?? 10;
|
||||
renderServerStats();
|
||||
}
|
||||
@@ -1458,7 +1084,7 @@ router.get('/', (req, res) => {
|
||||
label +
|
||||
'</div><div class=\"module-desc\">' +
|
||||
(item.label || label) +
|
||||
' • ' +
|
||||
' âÃÂâ ' +
|
||||
(item.format || '{label}: {value}') +
|
||||
'</div>';
|
||||
const buttons = document.createElement('div');
|
||||
@@ -1566,7 +1192,7 @@ router.get('/', (req, res) => {
|
||||
actions.className = 'row';
|
||||
const del = document.createElement('button');
|
||||
del.className = 'danger-btn';
|
||||
del.textContent = 'Löschen';
|
||||
del.textContent = 'LÃÂÃÂÃÂöschen';
|
||||
del.addEventListener('click', async () => {
|
||||
await deleteService(svc.id);
|
||||
});
|
||||
@@ -1624,7 +1250,7 @@ router.get('/', (req, res) => {
|
||||
if (res.ok) {
|
||||
await loadStatuspage();
|
||||
} else {
|
||||
showToast('Service löschen fehlgeschlagen', true);
|
||||
showToast('Service lÃÂÃÂÃÂöschen fehlgeschlagen', true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1902,7 +1528,7 @@ router.get('/', (req, res) => {
|
||||
'</div>' +
|
||||
'<div class=\"ticket-meta\">User: ' +
|
||||
(t.userId || '-') +
|
||||
(t.claimedBy ? ' · Supporter: ' + t.claimedBy : '') +
|
||||
(t.claimedBy ? ' ÃÂ÷ Supporter: ' + t.claimedBy : '') +
|
||||
'</div>';
|
||||
const select = document.createElement('select');
|
||||
select.innerHTML =
|
||||
@@ -2016,14 +1642,14 @@ router.get('/', (req, res) => {
|
||||
edit.addEventListener('click', () => fillAutomationForm(r));
|
||||
const del = document.createElement('button');
|
||||
del.className = 'danger-btn';
|
||||
del.textContent = 'Löschen';
|
||||
del.textContent = 'LÃÂöschen';
|
||||
del.addEventListener('click', async () => {
|
||||
const res = await fetch('/api/automations/' + r.id, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ guildId: currentGuild })
|
||||
});
|
||||
showToast(res.ok ? 'Regel gelöscht' : 'Löschen fehlgeschlagen', !res.ok);
|
||||
showToast(res.ok ? 'Regel gelÃÂöscht' : 'LÃÂöschen fehlgeschlagen', !res.ok);
|
||||
if (res.ok) loadAutomations();
|
||||
});
|
||||
actions.appendChild(edit);
|
||||
@@ -2083,14 +1709,14 @@ router.get('/', (req, res) => {
|
||||
edit.addEventListener('click', () => fillKbForm(a));
|
||||
const del = document.createElement('button');
|
||||
del.className = 'danger-btn';
|
||||
del.textContent = 'Löschen';
|
||||
del.textContent = 'LÃÂöschen';
|
||||
del.addEventListener('click', async () => {
|
||||
const res = await fetch('/api/kb/' + a.id, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ guildId: currentGuild })
|
||||
});
|
||||
showToast(res.ok ? 'Artikel gelöscht' : 'Löschen fehlgeschlagen', !res.ok);
|
||||
showToast(res.ok ? 'Artikel gelÃÂöscht' : 'LÃÂöschen fehlgeschlagen', !res.ok);
|
||||
if (res.ok) loadKb();
|
||||
});
|
||||
actions.appendChild(edit);
|
||||
@@ -2263,7 +1889,7 @@ router.get('/', (req, res) => {
|
||||
(s.userId || '-') +
|
||||
'</strong></div><div class="muted">Ende: ' +
|
||||
formatDate(s.endedAt || Date.now()) +
|
||||
' · Dauer: ' +
|
||||
' ÃÂÃÂÃÂ÷ Dauer: ' +
|
||||
dur +
|
||||
'</div>';
|
||||
supportRecentList.appendChild(div);
|
||||
@@ -2321,9 +1947,9 @@ router.get('/', (req, res) => {
|
||||
(ev.repeatType || 'none') +
|
||||
'</span></div><div class="ticket-meta">Start: ' +
|
||||
formatDate(ev.startTime) +
|
||||
' · Channel: ' +
|
||||
' ÃÂÃÂÃÂ÷ Channel: ' +
|
||||
(ev.channelId || '-') +
|
||||
' · Anmeldungen: ' +
|
||||
' ÃÂÃÂÃÂ÷ Anmeldungen: ' +
|
||||
(ev._count?.signups ?? 0) +
|
||||
'</div>';
|
||||
const actions = document.createElement('div');
|
||||
@@ -2536,7 +2162,7 @@ router.get('/', (req, res) => {
|
||||
meta.className = 'module-meta';
|
||||
const descParts = ['Channel: ' + (set.channelId || '-')];
|
||||
if (set.messageId) descParts.push('Message: ' + set.messageId);
|
||||
meta.innerHTML = '<div class="module-title">' + (set.title || 'Reaction Role') + '</div><div class="module-desc">' + descParts.join(' • ') + '</div>';
|
||||
meta.innerHTML = '<div class="module-title">' + (set.title || 'Reaction Role') + '</div><div class="module-desc">' + descParts.join(' • ') + '</div>';
|
||||
const actions = document.createElement('div');
|
||||
actions.className = 'row';
|
||||
const editBtn = document.createElement('button');
|
||||
|
||||
Reference in New Issue
Block a user