Refactor: Corregir uso de UTable en MetabaseCardsTable
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 50s

- Cambiar de slots personalizados a definición correcta de columnas con TanStack Table
- Usar accessorKey en lugar de key
- Implementar funciones header y cell con h() para renderizar componentes
- Eliminar slots #column-data y migrar a patrón estándar de nuxt-ui
- Seguir mismo patrón que VistaTablaIngresos.vue y VistaTablaClientes.vue

Esto corrige el problema donde los datos no se mostraban en la tabla de la página metabase-debug
This commit is contained in:
2025-10-31 09:52:59 -06:00
parent a6a13869ff
commit 7d074c8dd8

View File

@@ -25,66 +25,11 @@
<!-- Table -->
<UTable
:rows="filteredCards"
:data="filteredCards"
:columns="columns"
:loading="loading"
@select="selectCard"
>
<template #id-data="{ row }">
<UBadge color="gray" variant="subtle">{{ row.id }}</UBadge>
</template>
<template #name-data="{ row }">
<div>
<div class="font-medium text-[var(--brand-text)]">{{ row.name }}</div>
<div v-if="row.description" class="text-xs text-[var(--brand-text-muted)] truncate max-w-md">
{{ row.description }}
</div>
</div>
</template>
<template #query_type-data="{ row }">
<UBadge :color="getQueryTypeColor(row.query_type || row.dataset_query?.type)">
{{ row.query_type || row.dataset_query?.type || 'N/A' }}
</UBadge>
</template>
<template #database_id-data="{ row }">
<span class="text-sm text-[var(--brand-text)]">{{ row.database_id || 'N/A' }}</span>
</template>
<template #actions-data="{ row }">
<div class="flex flex-wrap gap-1">
<UButton
@click.stop="executeCard(row)"
:loading="executingCards.has(row.id)"
:ui="{ base: 'bg-[var(--brand-primary-strong)] text-[var(--brand-bg)] border border-[var(--brand-primary)] hover:bg-[var(--brand-primary)] hover:border-[var(--brand-accent)] disabled:opacity-50 disabled:cursor-not-allowed' }"
size="xs"
>
Ejecutar
</UButton>
<UButton
@click.stop="executeCachedCard(row)"
:loading="executingCachedCards.has(row.id)"
color="gray"
variant="ghost"
size="xs"
>
Caché
</UButton>
<UDropdown :items="getExportItems(row)">
<UButton
color="gray"
variant="ghost"
size="xs"
icon="i-heroicons-arrow-down-tray"
/>
</UDropdown>
</div>
</template>
</UTable>
@select="(row) => selectCard(row.original)"
/>
<!-- Results Modal -->
<UModal v-model="showResults">
@@ -149,6 +94,9 @@
</template>
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
const props = defineProps<{
cards: any[]
loading?: boolean
@@ -158,6 +106,10 @@ const emit = defineEmits<{
select: [card: any]
}>()
const UButton = resolveComponent('UButton')
const UBadge = resolveComponent('UBadge')
const UDropdown = resolveComponent('UDropdown')
const search = ref('')
const selectedFilter = ref('all')
const executingCards = ref(new Set<number>())
@@ -173,13 +125,95 @@ const filterOptions = [
{ value: 'query', label: 'Query Builder' }
]
const columns = [
{ key: 'id', label: 'ID' },
{ key: 'name', label: 'Nombre' },
{ key: 'query_type', label: 'Tipo' },
{ key: 'database_id', label: 'DB' },
{ key: 'actions', label: 'Acciones' }
]
const columns = computed((): TableColumn<Record<string, any>>[] => [
{
accessorKey: 'id',
header: 'ID',
cell: ({ row }) => {
return h(UBadge, {
color: 'gray',
variant: 'subtle',
label: row.original.id.toString()
})
}
},
{
accessorKey: 'name',
header: 'Nombre',
cell: ({ row }) => {
return h('div', {}, [
h('div', {
class: 'font-medium text-[var(--brand-text)]'
}, row.original.name),
row.original.description && h('div', {
class: 'text-xs text-[var(--brand-text-muted)] truncate max-w-md'
}, row.original.description)
])
}
},
{
accessorKey: 'query_type',
header: 'Tipo',
cell: ({ row }) => {
const type = row.original.query_type || row.original.dataset_query?.type || 'N/A'
return h(UBadge, {
color: getQueryTypeColor(type),
label: type
})
}
},
{
accessorKey: 'database_id',
header: 'DB',
cell: ({ row }) => {
return h('span', {
class: 'text-sm text-[var(--brand-text)]'
}, row.original.database_id?.toString() || 'N/A')
}
},
{
accessorKey: 'actions',
header: 'Acciones',
cell: ({ row }) => {
return h('div', {
class: 'flex flex-wrap gap-1'
}, [
h(UButton, {
onClick: (e: Event) => {
e.stopPropagation()
executeCard(row.original)
},
loading: executingCards.value.has(row.original.id),
ui: { base: 'bg-[var(--brand-primary-strong)] text-[var(--brand-bg)] border border-[var(--brand-primary)] hover:bg-[var(--brand-primary)] hover:border-[var(--brand-accent)] disabled:opacity-50 disabled:cursor-not-allowed' },
size: 'xs',
label: 'Ejecutar'
}),
h(UButton, {
onClick: (e: Event) => {
e.stopPropagation()
executeCachedCard(row.original)
},
loading: executingCachedCards.value.has(row.original.id),
color: 'gray',
variant: 'ghost',
size: 'xs',
label: 'Caché'
}),
h(UDropdown, {
items: getExportItems(row.original)
}, {
default: () => h(UButton, {
color: 'gray',
variant: 'ghost',
size: 'xs',
icon: 'i-heroicons-arrow-down-tray',
onClick: (e: Event) => e.stopPropagation()
})
})
])
}
}
])
const filteredCards = computed(() => {
let result = props.cards