Refactor: Corregir uso de UTable en MetabaseCardsTable
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 50s
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:
@@ -25,66 +25,11 @@
|
|||||||
|
|
||||||
<!-- Table -->
|
<!-- Table -->
|
||||||
<UTable
|
<UTable
|
||||||
:rows="filteredCards"
|
:data="filteredCards"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@select="selectCard"
|
@select="(row) => selectCard(row.original)"
|
||||||
>
|
/>
|
||||||
<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>
|
|
||||||
|
|
||||||
<!-- Results Modal -->
|
<!-- Results Modal -->
|
||||||
<UModal v-model="showResults">
|
<UModal v-model="showResults">
|
||||||
@@ -149,6 +94,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { h, resolveComponent } from 'vue'
|
||||||
|
import type { TableColumn } from '@nuxt/ui'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
cards: any[]
|
cards: any[]
|
||||||
loading?: boolean
|
loading?: boolean
|
||||||
@@ -158,6 +106,10 @@ const emit = defineEmits<{
|
|||||||
select: [card: any]
|
select: [card: any]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
const UButton = resolveComponent('UButton')
|
||||||
|
const UBadge = resolveComponent('UBadge')
|
||||||
|
const UDropdown = resolveComponent('UDropdown')
|
||||||
|
|
||||||
const search = ref('')
|
const search = ref('')
|
||||||
const selectedFilter = ref('all')
|
const selectedFilter = ref('all')
|
||||||
const executingCards = ref(new Set<number>())
|
const executingCards = ref(new Set<number>())
|
||||||
@@ -173,13 +125,95 @@ const filterOptions = [
|
|||||||
{ value: 'query', label: 'Query Builder' }
|
{ value: 'query', label: 'Query Builder' }
|
||||||
]
|
]
|
||||||
|
|
||||||
const columns = [
|
const columns = computed((): TableColumn<Record<string, any>>[] => [
|
||||||
{ key: 'id', label: 'ID' },
|
{
|
||||||
{ key: 'name', label: 'Nombre' },
|
accessorKey: 'id',
|
||||||
{ key: 'query_type', label: 'Tipo' },
|
header: 'ID',
|
||||||
{ key: 'database_id', label: 'DB' },
|
cell: ({ row }) => {
|
||||||
{ key: 'actions', label: 'Acciones' }
|
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(() => {
|
const filteredCards = computed(() => {
|
||||||
let result = props.cards
|
let result = props.cards
|
||||||
|
|||||||
Reference in New Issue
Block a user