nuxtUI implementado

This commit is contained in:
2025-09-29 15:05:32 -06:00
parent 7225903fc4
commit f4621a0b70
3 changed files with 52 additions and 47 deletions

View File

@@ -0,0 +1,2 @@
@import "tailwindcss";
@import "@nuxt/ui";

View File

@@ -12,63 +12,52 @@
<form class="flex flex-col gap-6" @submit.prevent="executeRequest">
<div class="grid gap-4 lg:grid-cols-4">
<UFormGroup label="Tipo de consulta" name="type">
<USelectMenu
v-model="request.type"
:options="requestTypeOptions"
option-attribute="label"
value-attribute="value"
/>
</UFormGroup>
<UFormField label="Tipo de consulta" name="type">
<USelectMenu v-model="request.type" :items="requestTypeOptions" value-key="value" />
</UFormField>
<UFormGroup label="Ámbito" name="scope">
<USelectMenu
v-model="request.scope"
:options="scopeOptions"
option-attribute="label"
value-attribute="value"
/>
</UFormGroup>
<UFormField label="Ámbito" name="scope">
<USelectMenu v-model="request.scope" :items="scopeOptions" value-key="value" />
</UFormField>
<UFormGroup v-if="requiresTable" label="Tabla" name="table">
<UFormField v-if="requiresTable" label="Tabla" name="table">
<USelectMenu
v-model="request.table"
:options="tableOptions"
option-attribute="label"
value-attribute="value"
:items="tableOptions"
value-key="value"
placeholder="Selecciona una tabla"
/>
</UFormGroup>
</UFormField>
<UFormGroup v-if="showsLimit" label="Límite" name="limit">
<UFormField v-if="showsLimit" label="Límite" name="limit">
<UInput v-model.number="request.limit" type="number" min="1" max="500" />
</UFormGroup>
</UFormField>
<UFormGroup v-if="requiresRecordId" label="ID del registro" name="recordId">
<UFormField v-if="requiresRecordId" label="ID del registro" name="recordId">
<UInput v-model="request.recordId" placeholder="Introduce el ID exacto" />
</UFormGroup>
</UFormField>
<UFormGroup v-if="showsIdFilter" label="Filtrar por ID" name="filterId">
<UFormField v-if="showsIdFilter" label="Filtrar por ID" name="filterId">
<UInput v-model="request.filterId" placeholder="Opcional" />
</UFormGroup>
</UFormField>
<UFormGroup v-if="showsDateFilters" label="Fecha desde" name="createdFrom">
<UFormField v-if="showsDateFilters" label="Fecha desde" name="createdFrom">
<UInput v-model="request.createdFrom" type="date" />
</UFormGroup>
</UFormField>
<UFormGroup v-if="showsDateFilters" label="Fecha hasta" name="createdTo">
<UFormField v-if="showsDateFilters" label="Fecha hasta" name="createdTo">
<UInput v-model="request.createdTo" type="date" />
</UFormGroup>
</UFormField>
</div>
<div v-if="showQueryJson" class="space-y-2">
<UFormGroup label="Consulta avanzada (JSON)">
<UFormField label="Consulta avanzada (JSON)" name="queryJson">
<UTextarea
v-model="request.queryJson"
:rows="5"
placeholder='{ "filters": [{ "field": "estado", "operator": "eq", "value": "activo" }] }'
/>
</UFormGroup>
</UFormField>
<p v-if="queryState.error" class="text-sm text-red-300">{{ queryState.error }}</p>
<p v-else-if="queryState.encoded" class="text-xs text-slate-400">
Segmento codificado: <code class="rounded bg-slate-800 px-2 py-1">{{ queryState.encoded }}</code>
@@ -88,7 +77,7 @@
</UAlert>
<div class="flex justify-end gap-2">
<UButton color="gray" variant="soft" @click="resetForm" :disabled="loading">
<UButton color="neutral" variant="soft" @click="resetForm" :disabled="loading">
Limpiar
</UButton>
<UButton type="submit" :loading="loading">
@@ -199,11 +188,11 @@
</UBadge>
</template>
<template v-else-if="dataStatsCollection.length">
<UBadge v-for="item in dataStatsCollection" :key="item.table" color="gray">
<UBadge v-for="item in dataStatsCollection" :key="item.table" color="neutral">
{{ item.table }}: {{ item.count }} registros (límite {{ item.limit ?? 's/d' }})
</UBadge>
</template>
<UBadge v-else-if="tableData.length" color="gray">
<UBadge v-else-if="tableData.length" color="neutral">
{{ tableData.length }} registros visibles
</UBadge>
</div>
@@ -211,7 +200,8 @@
</template>
<div v-if="loading" class="flex items-center justify-center py-10">
<ULoadingIndicator size="lg" />
<span class="inline-flex h-8 w-8 animate-spin rounded-full border-2 border-slate-400 border-t-transparent align-middle" aria-hidden="true" />
<span class="sr-only">Cargando</span>
</div>
<div v-else-if="!hasDataResponse" class="py-10 text-center text-sm text-slate-400">
Ejecuta una consulta de datos para ver resultados aquí.
@@ -250,6 +240,7 @@
<script setup lang="ts">
import { computed, onMounted, reactive, ref, watch } from 'vue'
import { useRequestFetch } from '#imports'
type RequestType = 'data' | 'metadata'
type MetadataScope = 'all' | 'table' | 'record'
@@ -279,6 +270,11 @@ const dataScopeOptions: Option<DataScope>[] = [
{ label: 'Consulta avanzada', value: 'query' }
]
const DEFAULT_METADATA_SCOPE: MetadataScope = 'all'
const DEFAULT_DATA_SCOPE: DataScope = 'table'
const requestFetch = useRequestFetch()
const request = reactive<{
type: RequestType
scope: RequestScope
@@ -292,7 +288,7 @@ const request = reactive<{
}>(
{
type: 'data',
scope: 'table',
scope: DEFAULT_DATA_SCOPE,
table: '',
recordId: '',
filterId: '',
@@ -410,7 +406,7 @@ onMounted(async () => {
watch(
() => request.type,
(type) => {
request.scope = type === 'metadata' ? metadataScopeOptions[0].value : dataScopeOptions[0].value
request.scope = type === 'metadata' ? DEFAULT_METADATA_SCOPE : DEFAULT_DATA_SCOPE
request.recordId = ''
request.filterId = ''
request.createdFrom = ''
@@ -429,8 +425,11 @@ watch(
() => {
if (!requiresTable.value) {
request.table = ''
} else if (!request.table && availableMetadata.value.length > 0) {
request.table = availableMetadata.value[0].table
} else if (!request.table) {
const defaultTable = availableMetadata.value[0]?.table
if (defaultTable) {
request.table = defaultTable
}
}
if (!requiresRecordId.value) {
@@ -450,11 +449,14 @@ watch(
async function loadAvailableMetadata() {
try {
const metadata = await $fetch('/api/metadata')
const metadata = await requestFetch('/api/metadata')
if (Array.isArray(metadata)) {
availableMetadata.value = metadata
if (!request.table && metadata.length > 0 && requiresTable.value) {
request.table = metadata[0].table
if (!request.table && requiresTable.value) {
const firstTable = metadata[0]?.table
if (firstTable) {
request.table = firstTable
}
}
}
} catch (error) {
@@ -496,7 +498,7 @@ function clearResults() {
}
function resetForm() {
request.scope = request.type === 'metadata' ? metadataScopeOptions[0].value : dataScopeOptions[0].value
request.scope = request.type === 'metadata' ? DEFAULT_METADATA_SCOPE : DEFAULT_DATA_SCOPE
request.table = availableMetadata.value[0]?.table ?? ''
request.recordId = ''
request.filterId = ''
@@ -595,7 +597,7 @@ async function executeRequest() {
errorMessage.value = null
try {
const response = await $fetch(requestConfig.url, {
const response = await requestFetch(requestConfig.url, {
query: requestConfig.query
})

View File

@@ -3,6 +3,7 @@ export default defineNuxtConfig({
ssr: false,
compatibilityDate: '2025-07-15',
devtools: { enabled: true },
css: ['~/assets/css/main.css'],
modules: ['@nuxt/image', '@nuxt/ui', '@nuxt/test-utils'],
runtimeConfig: {
supabase: {