feat(system): page Status avec endpoint API Platform et composants Vue
- Nouveau domaine System/Domain/Model/SystemStatus (value object) - QueryHandler agrégeant métriques mangas, chapitres, jobs (global/24h/7j), stockage et sources - Endpoint GET /api/system/status via API Platform (singleton) - Calcul de l'espace disque par RecursiveDirectoryIterator sur public/images - Page Vue /system/status avec 6 cards (Mangas, Chapitres, Jobs, Stockage, Sources, Système) - Nettoyage du router : suppression des PlaceholderComponent et routes placeholder - Sidebar : suppression des entrées sans page réelle
This commit is contained in:
parent
c2b55e9018
commit
ca8791cc0d
@@ -0,0 +1,71 @@
|
||||
<template>
|
||||
<div class="flex flex-col h-full">
|
||||
<Toolbar :config="toolbarConfig" />
|
||||
|
||||
<div class="overflow-y-auto flex-1">
|
||||
<!-- Loading -->
|
||||
<div v-if="loading" class="flex justify-center py-12">
|
||||
<div class="animate-spin h-10 w-10 border-b-2 border-blue-500 rounded-full"></div>
|
||||
</div>
|
||||
|
||||
<!-- Error -->
|
||||
<div v-else-if="error" class="px-6 py-8">
|
||||
<div class="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-700 p-4 rounded">
|
||||
<div class="flex items-center">
|
||||
<ExclamationCircleIcon class="w-5 h-5 text-red-400 mr-2 shrink-0" />
|
||||
<p class="text-red-800 dark:text-red-200">{{ error }}</p>
|
||||
</div>
|
||||
<button
|
||||
@click="statusStore.loadStatus()"
|
||||
class="mt-3 px-4 py-2 bg-red-600 text-white hover:bg-red-700 rounded">
|
||||
Réessayer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Données -->
|
||||
<div v-else-if="status" class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4 p-4">
|
||||
<MangasStatusCard :status="status" />
|
||||
<ChaptersStatusCard :status="status" />
|
||||
<JobsStatusCard :status="status" />
|
||||
<StorageStatusCard :status="status" />
|
||||
<SourcesStatusCard :status="status" />
|
||||
<SystemInfoCard :status="status" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ArrowPathIcon, ExclamationCircleIcon } from '@heroicons/vue/24/outline';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { computed, onMounted } from 'vue';
|
||||
import Toolbar from '../../../../shared/components/ui/Toolbar.vue';
|
||||
import { useStatusStore } from '../../application/store/statusStore';
|
||||
import ChaptersStatusCard from '../components/ChaptersStatusCard.vue';
|
||||
import JobsStatusCard from '../components/JobsStatusCard.vue';
|
||||
import MangasStatusCard from '../components/MangasStatusCard.vue';
|
||||
import SourcesStatusCard from '../components/SourcesStatusCard.vue';
|
||||
import StorageStatusCard from '../components/StorageStatusCard.vue';
|
||||
import SystemInfoCard from '../components/SystemInfoCard.vue';
|
||||
|
||||
const statusStore = useStatusStore();
|
||||
const { status, loading, error } = storeToRefs(statusStore);
|
||||
|
||||
onMounted(() => statusStore.loadStatus());
|
||||
|
||||
const toolbarConfig = computed(() => ({
|
||||
leftSection: [
|
||||
{ type: 'label', text: 'Statut système', class: 'text-sm font-medium' },
|
||||
],
|
||||
rightSection: [
|
||||
{
|
||||
type: 'button',
|
||||
icon: ArrowPathIcon,
|
||||
label: 'Rafraîchir',
|
||||
disabled: loading.value,
|
||||
onClick: () => statusStore.loadStatus(),
|
||||
},
|
||||
],
|
||||
}));
|
||||
</script>
|
||||
Reference in New Issue
Block a user