[deploy] fix ticket dashboard tabs/icons
All checks were successful
Deploy Discord Bot / deploy (push) Successful in 37s

This commit is contained in:
Pascal Prießnitz
2025-12-03 14:19:38 +01:00
parent a02aede837
commit 935a48fc17

View File

@@ -1,4 +1,4 @@
import { Router } from 'express';
import { Router } from 'express';
const router = Router();
@@ -43,18 +43,18 @@ 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="#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="#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>
@@ -330,10 +330,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"><EFBFBD>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"><EFBFBD>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>
@@ -346,7 +346,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<EFBFBD>hlen, Details im Modal. Plus <EFBFBD>ffnet Panel-Erstellung.</p>
</div>
<div class="row" style="gap:10px;">
<button class="secondary-btn" id="openSupportLogin" type="button">Support-Login Einstellungen</button>
@@ -361,7 +361,7 @@ router.get('/', (req, res) => {
<p class="section-title">Support-Login Status</p>
<p class="section-sub">Aktive Supporter und letzte Sessions.</p>
</div>
<button class="icon-button" id="refreshSupportStatus"></button>
<button class="icon-button" id="refreshSupportStatus">?</button>
</div>
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(240px,1fr)); gap:12px;">
<div>
@@ -381,7 +381,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 <EFBFBD>ndern.</p>
</div>
</div>
<div class="grid" style="grid-template-columns: repeat(auto-fit, minmax(240px,1fr)); gap:12px;" id="pipelineGrid">
@@ -430,7 +430,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<EFBFBD>r Ticket-Aktionen.</p>
</div>
<button class="secondary-btn" id="addAutomation">Neue Regel</button>
</div>
@@ -467,7 +467,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<EFBFBD>r Self-Service.</p>
</div>
<button class="secondary-btn" id="addKb">Neuer Artikel</button>
</div>
@@ -586,7 +586,7 @@ router.get('/', (req, res) => {
</div>
<div class="form-field">
<label class="form-label">Embed Footer</label>
<input id="welcomeFooter" placeholder="Schön, dass du da bist!" />
<input id="welcomeFooter" placeholder="Schön, dass du da bist!" />
</div>
</div>
<div class="form-field">
@@ -609,7 +609,7 @@ router.get('/', (req, res) => {
<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-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>
@@ -736,7 +736,7 @@ router.get('/', (req, res) => {
</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>
<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;">
@@ -810,7 +810,7 @@ router.get('/', (req, res) => {
<section class="card">
<div class="row" style="justify-content:space-between;">
<div>
<p class="section-title">Aktivität (letzte 24h)</p>
<p class="section-title">Aktivität (letzte 24h)</p>
<p class="section-sub">Events/Commands pro Stunde</p>
</div>
</div>
@@ -820,7 +820,7 @@ router.get('/', (req, res) => {
<div class="row" style="justify-content:space-between;">
<div>
<p class="section-title">Logs</p>
<p class="section-sub">Neueste Einträge</p>
<p class="section-sub">Neueste Einträge</p>
</div>
</div>
<ul class="log-list" id="adminLogs"></ul>
@@ -847,13 +847,13 @@ router.get('/', (req, res) => {
</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>
@@ -1419,7 +1419,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);
});
@@ -1477,7 +1477,7 @@ router.get('/', (req, res) => {
if (res.ok) {
await loadStatuspage();
} else {
showToast('Service löschen fehlgeschlagen', true);
showToast('Service löschen fehlgeschlagen', true);
}
}
@@ -1755,7 +1755,7 @@ router.get('/', (req, res) => {
'</div>' +
'<div class=\"ticket-meta\">User: ' +
(t.userId || '-') +
(t.claimedBy ? ' · Supporter: ' + t.claimedBy : '') +
(t.claimedBy ? ' <EFBFBD> Supporter: ' + t.claimedBy : '') +
'</div>';
const select = document.createElement('select');
select.innerHTML =
@@ -1869,14 +1869,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<EFBFBD>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<EFBFBD>scht' : 'L<EFBFBD>schen fehlgeschlagen', !res.ok);
if (res.ok) loadAutomations();
});
actions.appendChild(edit);
@@ -1936,14 +1936,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<EFBFBD>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<EFBFBD>scht' : 'L<EFBFBD>schen fehlgeschlagen', !res.ok);
if (res.ok) loadKb();
});
actions.appendChild(edit);
@@ -2116,7 +2116,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);
@@ -2174,9 +2174,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');
@@ -2389,7 +2389,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');
@@ -2638,11 +2638,11 @@ router.get('/', (req, res) => {
const actionType = document.getElementById('automationActionType')?.value;
const actionVal = document.getElementById('automationActionValue')?.value;
const active = getSwitch(document.getElementById('automationActive'));
const condition: any = {};
const condition = {};
if (condType === 'category') condition.category = condVal;
if (condType === 'status') condition.status = condVal;
if (condType === 'age') condition.minHours = Number(condVal || 0);
const action: any = { type: actionType };
const action = { type: actionType };
if (actionType === 'pingRole') action.roleId = actionVal;
if (actionType === 'reminder') action.message = actionVal;
if (actionType === 'flag') action.status = actionVal;