users: AG Grid reemplazado por tabla nativa paginada + QA indicators
- UsersView: tabla nativa con busqueda, paginacion (15/page), iniciales - UsersView: eliminada dependencia ag-grid (mantenida en bundle por otros modulos) - DashboardView: QA metrics con desglose auto/parcial/manual - DashboardView: seccion expandible con planes QA detallados - qa-analyzer: fix field name automatizable - ToDo: K-09 eliminada
This commit is contained in:
@@ -4,7 +4,7 @@ import { useI18n } from 'vue-i18n'
|
||||
import { useProjectsStore } from '@/stores/projects'
|
||||
import { useWorkItemsStore } from '@/stores/workitems'
|
||||
import { getTypeLabel, getTypeColor, getTypeIcon } from '@/services/hierarchy'
|
||||
import { Activity, FileText, Layers, Clock, Info, AlertTriangle, Plus, Brain, Sparkles, Loader2, CheckCircle2, XCircle, Send } from 'lucide-vue-next'
|
||||
import { Activity, FileText, Layers, Clock, Info, AlertTriangle, Plus, Brain, Sparkles, Loader2, CheckCircle2, XCircle, Send, ChevronDown } from 'lucide-vue-next'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import HuDrafts from '@/components/HuDrafts.vue'
|
||||
import AiProjectChat from '@/components/AiProjectChat.vue'
|
||||
@@ -38,6 +38,22 @@ const qaPlans = ref<any[]>([])
|
||||
const generatingQA = ref<string | null>(null)
|
||||
const expandedQA = ref<string | null>(null)
|
||||
|
||||
const qaMetrics = computed(() => {
|
||||
const plans = qaPlans.value
|
||||
let auto = 0, manual = 0, parcial = 0, totalCases = 0
|
||||
for (const p of plans) {
|
||||
const plan = parseQAPlan(p)
|
||||
if (!plan) continue
|
||||
for (const tc of plan.testCases) {
|
||||
totalCases++
|
||||
if (tc.automatizable === 'SÍ') auto++
|
||||
else if (tc.automatizable === 'MANUAL') manual++
|
||||
else parcial++
|
||||
}
|
||||
}
|
||||
return { total: plans.length, auto, manual, parcial, totalCases }
|
||||
})
|
||||
|
||||
async function loadQAPlans(projectId: number) {
|
||||
qaPlans.value = await getQAPlans(projectId)
|
||||
}
|
||||
@@ -58,6 +74,10 @@ function parseQAPlan(record: any): HUQAPlan | null {
|
||||
try { return JSON.parse(record.plan) as HUQAPlan } catch { return null }
|
||||
}
|
||||
|
||||
function toggleQAExpand(id: string) {
|
||||
expandedQA.value = expandedQA.value === id ? null : id
|
||||
}
|
||||
|
||||
function qaBadgeColor(a: string) {
|
||||
if (a === 'SÍ') return 'text-green-600 border-green-300'
|
||||
if (a === 'MANUAL') return 'text-red-600 border-red-300'
|
||||
@@ -284,8 +304,13 @@ const statusLabel = (status: unknown) => {
|
||||
<CheckCircle2 class="size-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="text-2xl font-bold">{{ qaPlans.length }}</div>
|
||||
<p class="text-xs text-muted-foreground">Planes QA generados</p>
|
||||
<div class="text-2xl font-bold">{{ qaMetrics.total }}</div>
|
||||
<p class="text-xs text-muted-foreground">Planes QA · {{ qaMetrics.totalCases }} casos</p>
|
||||
<div class="flex gap-2 mt-1.5 text-[10px]">
|
||||
<span class="text-green-600 dark:text-green-400">{{ qaMetrics.auto }} auto</span>
|
||||
<span class="text-amber-600 dark:text-amber-400">{{ qaMetrics.parcial }} parcial</span>
|
||||
<span class="text-red-600 dark:text-red-400">{{ qaMetrics.manual }} manual</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -441,6 +466,39 @@ const statusLabel = (status: unknown) => {
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- QA Plans -->
|
||||
<Card v-if="qaPlans.length > 0" id="dashboard-qa-plans">
|
||||
<CardHeader class="pb-2">
|
||||
<CardTitle class="text-sm font-medium flex items-center gap-2">
|
||||
<CheckCircle2 class="size-4" />
|
||||
Planes QA · {{ qaPlans.length }}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent class="space-y-2">
|
||||
<div v-for="p in qaPlans" :key="p.id" class="border rounded-lg p-3 text-sm">
|
||||
<div class="flex items-center justify-between cursor-pointer" @click="toggleQAExpand(p.id)">
|
||||
<span class="font-medium">{{ p.huTitle }}</span>
|
||||
<ChevronDown class="size-4 text-muted-foreground transition-transform" :class="expandedQA === p.id ? 'rotate-180' : ''" />
|
||||
</div>
|
||||
<div v-if="expandedQA === p.id" class="mt-2 space-y-2">
|
||||
<template v-if="parseQAPlan(p) as HUQAPlan">
|
||||
<div class="text-xs text-muted-foreground">{{ (parseQAPlan(p) as HUQAPlan).acceptanceCriteria?.length || 0 }} criterios, {{ (parseQAPlan(p) as HUQAPlan).testCases.length }} casos de prueba</div>
|
||||
<table class="w-full text-xs">
|
||||
<thead><tr class="text-muted-foreground"><th class="text-left py-1">Prueba</th><th class="text-left py-1">Tipo</th><th class="text-left py-1">Herramienta</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="(tc, i) in (parseQAPlan(p) as HUQAPlan).testCases" :key="i" class="border-t">
|
||||
<td class="py-1 pr-2">{{ tc.description }}</td>
|
||||
<td class="py-1 pr-2"><Badge variant="outline" :class="qaBadgeColor(tc.automatizable)" class="text-[10px]">{{ tc.automatizable }}</Badge></td>
|
||||
<td class="py-1 text-muted-foreground">{{ tc.tool }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<!-- Borradores (Tauri) -->
|
||||
<HuDrafts v-if="project" :initiative-id="project.id" />
|
||||
|
||||
|
||||
Reference in New Issue
Block a user