Feature: Filtros toggleables para todos los tipos de sesión
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 26s

- Activas: visibles por defecto, click para ocultar
- Finalizadas: ocultas por defecto, click para mostrar
- Stale: ocultas por defecto, click para mostrar
- Indicador visual con ícono ojo abierto/cerrado y ring highlight
- Mensaje informativo de sesiones ocultas por tipo
This commit is contained in:
2025-11-25 01:29:16 -06:00
parent b3f7de1442
commit b441b13320

View File

@@ -261,10 +261,16 @@ const pagedDevices = computed(() => devicesAll.value.slice(devicePage.value*page
watch([devicesAll, () => layoutMode.value], () => { devicePage.value = 0; }); watch([devicesAll, () => layoutMode.value], () => { devicePage.value = 0; });
const sessionPage = ref(0); const sessionPage = ref(0);
const showActiveSessions = ref(true);
const showStaleSessions = ref(false); const showStaleSessions = ref(false);
const showStoppedSessions = ref(false);
const filteredSessions = computed(() => { const filteredSessions = computed(() => {
if (showStaleSessions.value) return sessions.value; return sessions.value.filter(s => {
return sessions.value.filter(s => s.status !== 'stale'); if (s.status === 'active' && !showActiveSessions.value) return false;
if (s.status === 'stale' && !showStaleSessions.value) return false;
if (s.status === 'stopped' && !showStoppedSessions.value) return false;
return true;
});
}); });
const pagedSessions = computed(() => filteredSessions.value.slice(sessionPage.value*pageSize, sessionPage.value*pageSize + pageSize)); const pagedSessions = computed(() => filteredSessions.value.slice(sessionPage.value*pageSize, sessionPage.value*pageSize + pageSize));
watch([filteredSessions, () => layoutMode.value], () => { sessionPage.value = 0; }); watch([filteredSessions, () => layoutMode.value], () => { sessionPage.value = 0; });
@@ -544,14 +550,40 @@ async function handleUserFormSubmit(data) {
<div v-else class="space-y-3"> <div v-else class="space-y-3">
<!-- Stats --> <!-- Stats -->
<div class="flex flex-wrap gap-3 mb-4"> <div class="flex flex-wrap gap-3 mb-4">
<Badge variant="pink" class="text-sm py-1.5 px-3"> <Badge
<svg class="size-4 mr-1.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> :variant="showActiveSessions ? 'pink' : 'secondary'"
<circle cx="12" cy="12" r="10"></circle> class="text-sm py-1.5 px-3 cursor-pointer select-none transition-all"
<polyline points="12 6 12 12 16 14"></polyline> :class="showActiveSessions ? 'ring-2 ring-pink-400/50' : 'opacity-60 hover:opacity-100'"
@click="showActiveSessions = !showActiveSessions"
:title="showActiveSessions ? 'Click para ocultar sesiones activas' : 'Click para mostrar sesiones activas'"
>
<svg v-if="showActiveSessions" class="size-3.5 mr-1.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle cx="12" cy="12" r="3"></circle>
</svg>
<svg v-else class="size-3.5 mr-1.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path>
<line x1="1" y1="1" x2="23" y2="23"></line>
</svg> </svg>
Activas: {{ sessionStats.active }} Activas: {{ sessionStats.active }}
</Badge> </Badge>
<Badge variant="secondary" class="text-sm py-1.5 px-3">Finalizadas: {{ sessionStats.stopped }}</Badge> <Badge
:variant="showStoppedSessions ? 'secondary' : 'secondary'"
class="text-sm py-1.5 px-3 cursor-pointer select-none transition-all"
:class="showStoppedSessions ? 'ring-2 ring-muted/50' : 'opacity-60 hover:opacity-100'"
@click="showStoppedSessions = !showStoppedSessions"
:title="showStoppedSessions ? 'Click para ocultar sesiones finalizadas' : 'Click para mostrar sesiones finalizadas'"
>
<svg v-if="showStoppedSessions" class="size-3.5 mr-1.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle cx="12" cy="12" r="3"></circle>
</svg>
<svg v-else class="size-3.5 mr-1.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path>
<line x1="1" y1="1" x2="23" y2="23"></line>
</svg>
Finalizadas: {{ sessionStats.stopped }}
</Badge>
<Badge <Badge
:variant="showStaleSessions ? 'warning' : 'secondary'" :variant="showStaleSessions ? 'warning' : 'secondary'"
class="text-sm py-1.5 px-3 cursor-pointer select-none transition-all" class="text-sm py-1.5 px-3 cursor-pointer select-none transition-all"
@@ -589,7 +621,13 @@ async function handleUserFormSubmit(data) {
<!-- Sessions Grid --> <!-- Sessions Grid -->
<div v-if="loading.sessions" class="text-muted">Cargando sesiones...</div> <div v-if="loading.sessions" class="text-muted">Cargando sesiones...</div>
<div v-else-if="!filteredSessions.length" class="text-muted text-center py-8"> <div v-else-if="!filteredSessions.length" class="text-muted text-center py-8">
{{ sessions.length ? 'No hay sesiones activas (hay ' + sessionStats.stale + ' stale ocultas)' : 'No hay sesiones' }} <template v-if="!sessions.length">No hay sesiones</template>
<template v-else>
No hay sesiones visibles
<span v-if="sessionStats.active && !showActiveSessions" class="block text-xs mt-1">{{ sessionStats.active }} activas ocultas</span>
<span v-if="sessionStats.stopped && !showStoppedSessions" class="block text-xs mt-1">{{ sessionStats.stopped }} finalizadas ocultas</span>
<span v-if="sessionStats.stale && !showStaleSessions" class="block text-xs mt-1">{{ sessionStats.stale }} stale ocultas</span>
</template>
</div> </div>
<div v-else class="grid grid-cols-[repeat(auto-fill,minmax(320px,1fr))] gap-3"> <div v-else class="grid grid-cols-[repeat(auto-fill,minmax(320px,1fr))] gap-3">
<Card v-for="s in pagedSessions" :key="s.id" :class="['p-4', s.status === 'active' && 'border-pink-400/30 bg-pink-400/5']"> <Card v-for="s in pagedSessions" :key="s.id" :class="['p-4', s.status === 'active' && 'border-pink-400/30 bg-pink-400/5']">