feat: add bot restart functionality via API and Discord command
This commit is contained in:
7 files changed
+172
-5
No files matched your search
@@ -40,6 +40,7 @@ function post<T>(path: string, body?: unknown): Promise<T> {
|
||||
|
||||
export const api = {
|
||||
status: () => request<BotStatus>('/api/status'),
|
||||
restart: () => post<{ status: string }>('/api/restart'),
|
||||
|
||||
connect: (channelId: string) => post('/api/connect', { channel_id: channelId }),
|
||||
disconnect: () => post('/api/disconnect'),
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { RotateCw } from 'lucide-vue-next'
|
||||
import type { BotStatus, GuildSettings } from '@/types/status'
|
||||
import { api } from '@/api/client'
|
||||
import { useToasts } from '@/composables/useToasts'
|
||||
|
||||
const props = defineProps<{
|
||||
status: BotStatus | null
|
||||
@@ -9,6 +12,11 @@ const props = defineProps<{
|
||||
}>()
|
||||
defineEmits<{ selectGuild: [guildId: string] }>()
|
||||
|
||||
const { notify } = useToasts()
|
||||
const isRestarting = ref(false)
|
||||
const restartInitiatedAt = ref<number | null>(null)
|
||||
let restartTimer: number | null = null
|
||||
|
||||
const activeChannel = computed(() => props.status?.active_voice_channel ?? null)
|
||||
|
||||
const label = computed(() =>
|
||||
@@ -16,6 +24,43 @@ const label = computed(() =>
|
||||
? `Połączony: ${activeChannel.value.channel_name}`
|
||||
: 'Rozłączony',
|
||||
)
|
||||
|
||||
async function handleRestart() {
|
||||
if (isRestarting.value) return
|
||||
if (!window.confirm('Czy na pewno chcesz zrestartować bota?')) return
|
||||
|
||||
isRestarting.value = true
|
||||
restartInitiatedAt.value = Date.now()
|
||||
notify('Wysyłanie polecenia restartu...', 'info')
|
||||
|
||||
try {
|
||||
await api.restart()
|
||||
notify('Wysłano polecenie. Restartowanie bota...', 'info')
|
||||
} catch {
|
||||
notify('Wysłano polecenie restartu.', 'info')
|
||||
}
|
||||
|
||||
if (restartTimer !== null) clearTimeout(restartTimer)
|
||||
restartTimer = window.setTimeout(() => {
|
||||
isRestarting.value = false
|
||||
restartInitiatedAt.value = null
|
||||
}, 15000)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.status,
|
||||
() => {
|
||||
if (isRestarting.value && restartInitiatedAt.value && Date.now() - restartInitiatedAt.value > 3000) {
|
||||
isRestarting.value = false
|
||||
restartInitiatedAt.value = null
|
||||
if (restartTimer !== null) {
|
||||
clearTimeout(restartTimer)
|
||||
restartTimer = null
|
||||
}
|
||||
notify('Bot został uruchomiony ponownie!', 'success')
|
||||
}
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -56,6 +101,19 @@ const label = computed(() =>
|
||||
/>
|
||||
<span>{{ label }}</span>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-secondary btn-restart"
|
||||
:disabled="isRestarting"
|
||||
:title="isRestarting ? 'Restartowanie bota...' : 'Zrestartuj bota'"
|
||||
@click="handleRestart"
|
||||
>
|
||||
<RotateCw
|
||||
:size="16"
|
||||
:class="{ 'spin-icon': isRestarting }"
|
||||
/>
|
||||
<span>{{ isRestarting ? 'Restart...' : 'Restart' }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
@@ -67,10 +125,32 @@ const label = computed(() =>
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
display: flex;
|
||||
.btn-restart {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 16px;
|
||||
border-radius: 30px;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: var(--transition-smooth);
|
||||
}
|
||||
|
||||
.btn-restart:hover:not(:disabled) {
|
||||
border-color: rgba(239, 68, 68, 0.4);
|
||||
color: #fca5a5;
|
||||
background: rgba(239, 68, 68, 0.12);
|
||||
box-shadow: 0 0 12px rgba(239, 68, 68, 0.2);
|
||||
}
|
||||
|
||||
.btn-restart:disabled {
|
||||
opacity: 0.65;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.spin-icon {
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -85,5 +165,10 @@ const label = computed(() =>
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.btn-restart {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user