feat(frontend): composables ze stanem panelu

Logika, która w app.js żyła w zmiennych globalnych, trafia do czterech
composables o wyraźnym zakresie odpowiedzialności:

- useBotStatus     jedno połączenie WebSocket na aplikację, z licznikiem
                   subskrybentów i ponawianiem po zerwaniu. Flaga paused
                   wstrzymuje aktualizacje na czas przeciągania utworów.
- useToasts        kolejka powiadomień wraz z helperem run(), który
                   opakowuje wywołanie API w parę komunikatów sukces/błąd.
- useTrackProgress płynny pasek postępu - między pakietami z serwera czas
                   dopisujemy lokalnie, a każdy pakiet resynchronizuje licznik.
- useUploads       serwerowa baza plików, współdzielona przez kafelek na
                   pulpicie i okno z pełną listą.

Dochodzi też utils/plural.ts z polską odmianą liczebników, zamiast
powtarzanego w kilku miejscach warunku count < 5.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
lgooseandClaude Bot committed 2026-08-21 01:08:04 +02:00
1 parent 6bfa9b2a77
commit 119bff00a3
5 files changed
+227

No files matched your search

+48
View File
@@ -0,0 +1,48 @@
import { ref } from 'vue'
import { api } from '@/api/client'
import type { UploadedFile } from '@/types/status'
import { useToasts } from '@/composables/useToasts'
/** Ile plików pokazuje kafelek na pulpicie - reszta czeka w oknie modalnym. */
export const DASHBOARD_FILE_LIMIT = 10
const files = ref<UploadedFile[]>([])
const uploading = ref(false)
const uploadLabel = ref('')
/** Serwerowa baza plików współdzielona przez kafelek i okno z pełną listą. */
export function useUploads() {
const { notify, run } = useToasts()
async function refresh() {
try {
files.value = (await api.uploads()).files
} catch (error) {
console.error('Błąd pobierania plików:', error)
}
}
async function upload(selected: FileList) {
uploading.value = true
for (const file of Array.from(selected)) {
uploadLabel.value = `Przesyłanie: ${file.name}...`
await run(() => api.upload(file), `Przesłano plik: ${file.name}`, `Błąd przesyłania ${file.name}`)
}
uploading.value = false
uploadLabel.value = ''
await refresh()
}
async function remove(filename: string) {
if (await run(() => api.deleteUpload(filename), 'Usunięto plik z serwera', 'Nie udało się usunąć pliku')) {
await refresh()
}
}
async function enqueue(filename: string) {
await run(() => api.playFile(filename), 'Dodano plik do kolejki!', 'Błąd odtwarzania')
await refresh()
}
return { files, uploading, uploadLabel, refresh, upload, remove, enqueue, notify }
}