BREAKING CHANGE: nouvelle architecture frontend avec layout sidebar, système de thèmes et routes restructurées ### Frontend - nouveau layout global `AppLayout.vue` avec sidebar de navigation inspirée Radarr/Sonarr - sidebar configurable via un objet `NavItem[]` avec support parents/enfants cliquables - 3 thèmes CSS (Indigo Électrique, Crimson Night, Teal Froid) persistés via localStorage - switcher de thème en bas de sidebar avec pastilles colorées - logo FanKarr cliquable, bouton déconnexion discret dans le header sidebar - badge animé sur "Activité" affichant le nombre de téléchargements en cours - migration complète vers Tailwind v4 avec variables CSS `@theme` - classes utilitaires globales : `btn-primary`, `btn-secondary`, `settings-card`, `settings-input` ### Vues - `SeriesView` : barre colorée en bas des affiches (vert/bleu/orange), dropdown filtres, boutons taille S/M/L/XL persistés - `SerieView` : bouton état unique par épisode (↓/⟳/✓/✗), badges simplifiés, toast via `useToast` global - `ActivityView` : onglets pill, stats, toggle "masquer importés", polling silencieux - `DashboardView` : stats catalogue/importées/en cours/erreurs, torrents actifs, derniers imports - `SettingsView` découpée en 3 vues indépendantes : `DownloadClientView`, `MediaManagementView`, `CatalogueView` - `LogsView` déplacée dans `src/views/settings/` - `AuthView` : migré au système de thème ### Composants - `SidebarNavItem` : support badge, chevron masqué si badge présent - `SettingsToggle` : composant réutilisable `v-model` - `FolderPicker` : migré au thème, `Teleport` intégré - `ToastContainer` : déplacé en bas droite, groupement des toasts similaires avec badge count ### Router - `AppLayout` comme layout racine pour toutes les routes protégées - `/auth` reste hors layout - redirections `/` → `/series`, `/downloads` → `/activity` - `SettingsLayout` avec titre dynamique par route - scroll géré sur `<main id="main-scroll">` dans `AppLayout` ### Stores & composables - nouveau store `downloads` partagé pour le badge sidebar - `usePosterSize` : taille des affiches persistée en localStorage - `useToast` : groupement des toasts du même type, timer reset au lieu d'empilement ### Serveur - logs structurés via `logger` dans `auth.ts`, `organize.ts`, `organize-worker.ts`, `torrent-clients/index.ts`, `qbittorrent.ts`, `index.ts` - suppression des `console.log/error/warn` en faveur de `logger.info/warn/error/debug` - messages worker routés vers `logger` via `organize.ts` - logs `debug` pour les événements verbeux (healthcheck, skip, worker terminé)
79 lines
2.5 KiB
Vue
79 lines
2.5 KiB
Vue
<template>
|
|
<div class="flex flex-col gap-6">
|
|
|
|
<div>
|
|
<h2 class="text-base font-semibold text-primary">Catalogue Fankai</h2>
|
|
<p class="text-sm text-muted mt-1">
|
|
Données locales synchronisées depuis GitLab. Mise à jour automatique toutes les 6h.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Bannière données manquantes -->
|
|
<div
|
|
v-if="status.empty"
|
|
class="border border-accent/30 bg-accent-muted rounded-lg p-4 flex items-center justify-between gap-4"
|
|
>
|
|
<div>
|
|
<p class="text-xs text-accent font-medium mb-1">Données manquantes</p>
|
|
<p class="text-sm text-secondary">
|
|
{{ status.exists ? 'Le catalogue est vide.' : 'Aucun catalogue trouvé.' }}
|
|
Téléchargez les données pour utiliser FanKarr.
|
|
</p>
|
|
</div>
|
|
<button @click="update" :disabled="updating" class="btn-primary whitespace-nowrap">
|
|
{{ updating ? 'Téléchargement...' : 'Télécharger' }}
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Statut -->
|
|
<div class="settings-card">
|
|
<p class="text-xs text-muted mb-1">Statut</p>
|
|
<p class="text-sm text-primary font-medium">
|
|
{{ status.empty ? 'Aucune donnée chargée' : `${status.count} séries disponibles` }}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Action -->
|
|
<div>
|
|
<button @click="update" :disabled="updating" class="btn-primary">
|
|
{{ updating ? 'Mise à jour...' : 'Mettre à jour maintenant' }}
|
|
</button>
|
|
<p class="text-xs text-muted mt-2">Force la synchronisation sans attendre le cache de 6h.</p>
|
|
</div>
|
|
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue'
|
|
import { useToast } from '@/composables/useToast'
|
|
|
|
const { add: toast } = useToast()
|
|
|
|
const updating = ref(false)
|
|
const status = ref({ exists: false, count: 0, empty: true })
|
|
|
|
onMounted(async () => {
|
|
const res = await fetch('/api/torrents/status', { credentials: 'include' })
|
|
if (res.ok) status.value = await res.json()
|
|
})
|
|
|
|
async function update() {
|
|
updating.value = true
|
|
try {
|
|
const res = await fetch('/api/update', { method: 'POST', credentials: 'include' })
|
|
if (res.ok) {
|
|
const { count } = await res.json()
|
|
status.value = { exists: true, count, empty: count === 0 }
|
|
toast(`${count} séries chargées ✓`, 'success')
|
|
} else {
|
|
const { error } = await res.json()
|
|
toast(error ?? 'Erreur lors de la mise à jour', 'error')
|
|
}
|
|
} catch {
|
|
toast('Impossible de contacter le serveur', 'error')
|
|
} finally {
|
|
updating.value = false
|
|
}
|
|
}
|
|
</script> |