136 lines
8.6 KiB
HTML
136 lines
8.6 KiB
HTML
{% extends "sidebar.html" %}
|
|
|
|
{% block title %}AstraOS — Discord Bots{% endblock %}
|
|
|
|
{% block head %}
|
|
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
|
<script src="https://cdn.socket.io/4.7.5/socket.io.min.js"></script>
|
|
<style>
|
|
/* Toggle Switch */
|
|
.switch { position: relative; display: inline-block; width: 50px; height: 28px; }
|
|
.switch input { opacity: 0; width: 0; height: 0; }
|
|
.slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #4a5568; transition: .4s; border-radius: 28px; }
|
|
.slider:before { position: absolute; content: ""; height: 20px; width: 20px; left: 4px; bottom: 4px; background-color: white; transition: .4s; border-radius: 50%; }
|
|
input:checked + .slider { background-color: #28a745; }
|
|
input:checked + .slider:before { transform: translateX(22px); }
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div x-data="{ showUploadModal: false, showDeleteModal: false, botToDelete: null }">
|
|
<main class="flex-1 p-8 space-y-10" id="mainContent">
|
|
<!-- HEADER -->
|
|
<header class="flex justify-between items-center mb-10">
|
|
<h2 class="text-4xl font-bold tracking-wide {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Discord Bot Management</h2>
|
|
<button @click="showUploadModal = true" class="font-bold py-2 px-4 rounded-lg transition text-white
|
|
{% if maintenance_active %}bg-yellow-600 hover:bg-yellow-700{% else %}bg-purple-600 hover:bg-purple-700{% endif %}">
|
|
+ Neuen Bot hochladen
|
|
</button>
|
|
</header>
|
|
|
|
<!-- BOT LIST -->
|
|
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{% for bot in bots %}
|
|
<div class="bg-black/40 rounded-xl backdrop-blur-lg p-6 flex flex-col justify-between
|
|
{% if maintenance_active %}border border-yellow-500/30{% else %}border border-purple-500/20{% endif %}">
|
|
<div>
|
|
<div class="flex justify-between items-start">
|
|
<h3 class="text-2xl font-semibold mb-2 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">{{ bot.name }}</h3>
|
|
<span id="status-{{ bot._id }}" class="px-2 py-1 text-xs font-semibold rounded-full
|
|
{% if bot.status == 'running' %}bg-green-500/20 text-green-300{% else %}bg-red-500/20 text-red-300{% endif %}">
|
|
{{ bot.status }}
|
|
</span>
|
|
</div>
|
|
<p class="text-sm text-gray-400 mb-4">Filename: {{ bot.filename }}</p>
|
|
</div>
|
|
<div class="flex justify-between items-center gap-2 mt-4">
|
|
<label class="switch">
|
|
<input type="checkbox" class="bot-toggle" data-bot-id="{{ bot._id }}" {% if bot.status == 'running' %}checked{% endif %}>
|
|
<span class="slider"></span>
|
|
</label>
|
|
<div class="flex items-center gap-2">
|
|
<a href="{{ url_for('bot_console', bot_id=bot._id) }}" class="px-4 py-2 text-sm font-semibold rounded-lg transition text-white
|
|
{% if maintenance_active %}bg-yellow-600/80 hover:bg-yellow-700{% else %}bg-purple-600/80 hover:bg-purple-700{% endif %}">
|
|
Konsole
|
|
</a>
|
|
<button @click="botToDelete = '{{ bot._id }}'; showDeleteModal = true" class="px-3 py-2 text-sm font-semibold rounded-lg transition text-white bg-red-600/80 hover:bg-red-700">
|
|
Löschen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% else %}
|
|
<p class="text-gray-400 col-span-full text-center">Noch keine Bots hochgeladen.</p>
|
|
{% endfor %}
|
|
</div>
|
|
</main>
|
|
|
|
<!-- UPLOAD BOT MODAL -->
|
|
<div x-show="showUploadModal" @keydown.escape.window="showUploadModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
|
|
<div @click.away="showUploadModal = false" class="bg-gray-900 rounded-xl shadow-2xl p-8 w-full max-w-md
|
|
{% if maintenance_active %}border border-yellow-500/50{% else %}border border-purple-500/50{% endif %}">
|
|
<h3 class="text-2xl font-bold mb-6 {% if maintenance_active %}text-yellow-300{% else %}text-purple-300{% endif %}">Neuen Bot hochladen</h3>
|
|
<form action="{{ url_for('upload_bot') }}" method="POST" enctype="multipart/form-data" class="space-y-4">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
|
<div>
|
|
<label for="bot_name" class="block text-sm font-medium text-gray-300">Bot-Name</label>
|
|
<input type="text" name="bot_name" id="bot_name" required class="mt-1 w-full px-3 py-2 bg-gray-800 border border-gray-700 rounded-lg text-white focus:outline-none focus:ring-2 {% if maintenance_active %}focus:ring-yellow-500{% else %}focus:ring-purple-500{% endif %}">
|
|
</div>
|
|
<div>
|
|
<label for="bot_file" class="block text-sm font-medium text-gray-300">Bot-Datei (.py)</label>
|
|
<input type="file" name="bot_file" id="bot_file" required accept=".py" class="mt-1 w-full text-sm text-gray-400 file:mr-4 file:py-2 file:px-4 file:rounded-lg file:border-0 file:text-sm file:font-semibold {% if maintenance_active %}file:bg-yellow-600/20 file:text-yellow-300 hover:file:bg-yellow-600/30{% else %}file:bg-purple-600/20 file:text-purple-300 hover:file:bg-purple-600/30{% endif %}">
|
|
</div>
|
|
<div class="flex justify-end gap-4 pt-4">
|
|
<button type="button" @click="showUploadModal = false" class="px-4 py-2 rounded-lg text-gray-300 hover:bg-gray-700 transition">Abbrechen</button>
|
|
<button type="submit" class="px-4 py-2 font-semibold rounded-lg transition text-white
|
|
{% if maintenance_active %}bg-yellow-600 hover:bg-yellow-700{% else %}bg-purple-600 hover:bg-purple-700{% endif %}">Hochladen</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- DELETE CONFIRMATION MODAL -->
|
|
<div x-show="showDeleteModal" @keydown.escape.window="showDeleteModal = false" class="fixed inset-0 bg-black/70 backdrop-blur-sm flex items-center justify-center z-50" style="display: none;">
|
|
<div @click.away="showDeleteModal = false" class="bg-gray-900 border border-red-500/50 rounded-xl shadow-2xl p-8 w-full max-w-md">
|
|
<h3 class="text-2xl font-bold text-red-400 mb-4">Bot löschen</h3>
|
|
<p class="text-gray-300 mb-6">Möchten Sie diesen Bot wirklich endgültig löschen? Die Bot-Datei wird vom Server entfernt und diese Aktion kann nicht rückgängig gemacht werden.</p>
|
|
<form :action="'/delete_bot/' + botToDelete" method="POST" class="flex justify-end gap-4">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/>
|
|
<button type="button" @click="showDeleteModal = false" class="px-4 py-2 rounded-lg text-gray-300 hover:bg-gray-700 transition">Abbrechen</button>
|
|
<button type="submit" class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white font-semibold rounded-lg transition">Endgültig löschen</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
const socket = io();
|
|
|
|
socket.on('connect', () => {
|
|
console.log('Verbunden mit dem Server für Status-Updates.');
|
|
});
|
|
|
|
socket.on('status_update', (data) => {
|
|
const botId = data.bot_id;
|
|
const statusElement = document.getElementById(`status-${botId}`);
|
|
const toggle = document.querySelector(`.bot-toggle[data-bot-id="${botId}"]`);
|
|
|
|
if (statusElement && toggle) {
|
|
statusElement.textContent = data.status;
|
|
statusElement.className = `px-2 py-1 text-xs font-semibold rounded-full ${data.status === 'running' ? 'bg-green-500/20 text-green-300' : 'bg-red-500/20 text-red-300'}`;
|
|
toggle.checked = data.status === 'running';
|
|
}
|
|
});
|
|
|
|
document.querySelectorAll('.bot-toggle').forEach(toggle => {
|
|
toggle.addEventListener('change', () => {
|
|
const botId = toggle.dataset.botId;
|
|
const action = toggle.checked ? 'start' : 'stop';
|
|
socket.emit('toggle_bot', { bot_id: botId, action: action });
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|