Files
analiticaNucleo/nuxt4-app/app/pages/metabase-debug.vue
josedario87 c035c8a78f
All checks were successful
build-and-deploy / build (push) Successful in 43s
build-and-deploy / deploy (push) Successful in 3s
fix: corregir renderizado de tabs en metabase-debug
Corrección del bug visual donde todos los tabs se mostraban simultáneamente.
El problema era el uso incorrecto del slot #default en UTabs que causaba
que todos los contenidos se renderizaran a la vez, creando elementos duplicados.

Cambios:
- Cambiar de #default a slots nombrados específicos (#table, #cards, #panorama, #detail)
- Ahora solo se muestra el contenido del tab activo
- Elimina la duplicación de elementos
- Mejora la legibilidad y organización visual
2025-10-14 02:35:48 -06:00

211 lines
5.7 KiB
Vue

<template>
<div class="container mx-auto px-4 py-8">
<div class="space-y-6">
<!-- Header -->
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-4">
<div class="flex-1">
<h1 class="text-2xl sm:text-3xl font-bold">Metabase Debug</h1>
<p class="text-sm sm:text-base text-gray-600 dark:text-gray-400 mt-1">
Herramienta de debugging para queries de Metabase
</p>
</div>
<UButton
@click="refreshCards"
:loading="loading"
icon="i-heroicons-arrow-path"
color="primary"
variant="soft"
class="w-full sm:w-auto"
>
Actualizar
</UButton>
</div>
<!-- Stats -->
<div class="grid grid-cols-2 sm:grid-cols-2 md:grid-cols-4 gap-3 sm:gap-4">
<UCard>
<div class="text-center">
<div class="text-2xl sm:text-3xl font-bold text-primary">{{ cards.length }}</div>
<div class="text-xs sm:text-sm text-gray-600 dark:text-gray-400">Total Cards</div>
</div>
</UCard>
<UCard>
<div class="text-center">
<div class="text-2xl sm:text-3xl font-bold text-primary">{{ nativeQueries }}</div>
<div class="text-xs sm:text-sm text-gray-600 dark:text-gray-400">SQL Nativo</div>
</div>
</UCard>
<UCard>
<div class="text-center">
<div class="text-2xl sm:text-3xl font-bold text-green-600">{{ queryBuilderQueries }}</div>
<div class="text-xs sm:text-sm text-gray-600 dark:text-gray-400">Query Builder</div>
</div>
</UCard>
<UCard>
<div class="text-center">
<div class="text-2xl sm:text-3xl font-bold text-gray-600">{{ panoramaQueries.length }}/9</div>
<div class="text-xs sm:text-sm text-gray-600 dark:text-gray-400">Queries Panorama</div>
</div>
</UCard>
</div>
<!-- Error Display -->
<UAlert
v-if="error"
color="error"
variant="soft"
:title="error"
:close-button="{ icon: 'i-heroicons-x-mark-20-solid', color: 'error', variant: 'link' }"
@close="error = null"
/>
<!-- Tabs -->
<UTabs v-model="selectedTab" :items="tabs">
<!-- Table View -->
<template #table>
<div class="py-4">
<MetabaseCardsTable
:cards="cards"
:loading="loading"
@select="selectCard"
/>
</div>
</template>
<!-- Cards View -->
<template #cards>
<div class="py-4">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4">
<MetabaseCardDisplay
v-for="card in cards"
:key="card.id"
:card="card"
/>
</div>
</div>
</template>
<!-- Panorama Queries -->
<template #panorama>
<div class="py-4 space-y-4">
<UAlert
color="info"
variant="soft"
title="Queries del Panorama Facturador"
description="Estas son las 9 queries documentadas en METABASE_QUERIES_PANORAMA.md"
/>
<div class="grid grid-cols-1 gap-4">
<MetabaseCardDisplay
v-for="card in panoramaQueries"
:key="card.id"
:card="card"
/>
</div>
<UAlert
v-if="panoramaQueries.length < 9"
color="warning"
variant="soft"
:title="`Faltan ${9 - panoramaQueries.length} queries por encontrar`"
description="Busca en la tabla las queries que contengan 'panorama' en su nombre"
/>
</div>
</template>
<!-- Selected Card Detail -->
<template #detail>
<div v-if="selectedCard" class="py-4">
<MetabaseCardDisplay :card="selectedCard" />
</div>
</template>
</UTabs>
</div>
</div>
</template>
<script setup lang="ts">
const loading = ref(false)
const error = ref<string | null>(null)
const cards = ref<any[]>([])
const selectedCard = ref<any>(null)
const selectedTab = ref(0)
const tabs = [
{
key: 'table',
label: 'Vista Tabla',
icon: 'i-heroicons-table-cells'
},
{
key: 'cards',
label: 'Vista Cards',
icon: 'i-heroicons-squares-2x2'
},
{
key: 'panorama',
label: 'Queries Panorama',
icon: 'i-heroicons-chart-bar'
},
{
key: 'detail',
label: 'Detalle',
icon: 'i-heroicons-document-magnifying-glass',
disabled: !selectedCard.value
}
]
const nativeQueries = computed(() => {
return cards.value.filter(card => {
const type = card.query_type || card.dataset_query?.type
return type === 'native'
}).length
})
const queryBuilderQueries = computed(() => {
return cards.value.filter(card => {
const type = card.query_type || card.dataset_query?.type
return type === 'query'
}).length
})
const panoramaQueries = computed(() => {
return cards.value.filter(card =>
card.name?.toLowerCase().includes('panorama')
)
})
async function fetchCards() {
loading.value = true
error.value = null
try {
const result = await $fetch('/api/metabase/cards?f=all')
cards.value = Array.isArray(result) ? result : []
} catch (e: any) {
error.value = e.message || 'Error al cargar las cards de Metabase'
console.error('Error fetching cards:', e)
} finally {
loading.value = false
}
}
function refreshCards() {
fetchCards()
}
function selectCard(card: any) {
selectedCard.value = card
selectedTab.value = 3 // Switch to detail tab
}
// Load cards on mount
onMounted(() => {
fetchCards()
})
</script>