From 5ef2b2c8e558d508be68b0d0713d9524da44a6f7 Mon Sep 17 00:00:00 2001 From: Ricardo Gonzalez Date: Wed, 27 May 2026 13:48:07 -0500 Subject: [PATCH] agregar paginacion a /userstorys/ + redisenar dashboard de proyecto con epicas y HUs --- src/services/kappa-api.ts | 20 +++- src/stores/workitems.ts | 11 +- src/views/DashboardView.vue | 232 +++++++++++++++++++++--------------- 3 files changed, 157 insertions(+), 106 deletions(-) diff --git a/src/services/kappa-api.ts b/src/services/kappa-api.ts index a9bbcec..d4aff19 100644 --- a/src/services/kappa-api.ts +++ b/src/services/kappa-api.ts @@ -99,9 +99,23 @@ class KappaAPI { return this.request>('GET', `/employees/?page=${page}`) } - async getUserStories(initiativeId?: number): Promise { - const path = initiativeId ? `/userstorys/?initiative=${initiativeId}` : '/userstorys/' - return this.request('GET', path) + async getUserStories(initiativeId?: number, page = 1, pageSize = 100): Promise> { + const params = new URLSearchParams() + if (initiativeId) params.set('initiative', String(initiativeId)) + params.set('page', String(page)) + params.set('page_size', String(pageSize)) + return this.request>('GET', `/userstorys/?${params.toString()}`) + } + + async getAllUserStories(initiativeId: number): Promise { + const first = await this.getUserStories(initiativeId, 1, 100) + const all = [...first.results] + const totalPages = Math.ceil(first.count / 100) + for (let p = 2; p <= totalPages; p++) { + const page = await this.getUserStories(initiativeId, p, 100) + all.push(...page.results) + } + return all } async getEpicDevelopment(initiativeId: number, page = 1, pageSize = 50): Promise> { diff --git a/src/stores/workitems.ts b/src/stores/workitems.ts index e3a48c4..d49b751 100644 --- a/src/stores/workitems.ts +++ b/src/stores/workitems.ts @@ -51,18 +51,15 @@ export const useWorkItemsStore = defineStore('workitems', () => { try { const [stories, logs, plans, epicData] = await Promise.all([ - kappa.getUserStories(id).catch(() => [] as KappaUserStory[]), + kappa.getAllUserStories(id).catch(() => [] as KappaUserStory[]), kappa.getLogbooks(id).catch(() => [] as KappaLogbookEntry[]), kappa.getPlannings(id).catch(() => [] as KappaPlanningEntry[]), kappa.getAllEpicDevelopment(id).catch(() => [] as KappaEpicDevelopment[]), ]) - const storiesData = stories as KappaUserStory[] | { results?: KappaUserStory[] } - const logsData = logs as KappaLogbookEntry[] | { results?: KappaLogbookEntry[] } - const plansData = plans as KappaPlanningEntry[] | { results?: KappaPlanningEntry[] } - userStories.value = Array.isArray(storiesData) ? storiesData : (storiesData.results ?? []) - logbooks.value = Array.isArray(logsData) ? logsData : (logsData.results ?? []) - plannings.value = Array.isArray(plansData) ? plansData : (plansData.results ?? []) + userStories.value = stories + logbooks.value = Array.isArray(logs) ? logs : ((logs as any).results ?? []) + plannings.value = Array.isArray(plans) ? plans : ((plans as any).results ?? []) epics.value = epicData.map(epic => ({ ...epic, diff --git a/src/views/DashboardView.vue b/src/views/DashboardView.vue index c21b895..7af2826 100644 --- a/src/views/DashboardView.vue +++ b/src/views/DashboardView.vue @@ -2,9 +2,10 @@ import { computed, watch } from 'vue' import { useProjectsStore } from '@/stores/projects' import { useWorkItemsStore } from '@/stores/workitems' -import { Activity, CreditCard, FileText, Users } from 'lucide-vue-next' +import { Activity, FileText, Layers, Clock, ChevronRight } from 'lucide-vue-next' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' +import { Skeleton } from '@/components/ui/skeleton' import { Table, TableBody, @@ -29,42 +30,70 @@ watch( { immediate: true } ) -const recentSessions = computed(() => { - return [...workItems.logbooks] - .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()) - .slice(0, 5) -}) +const statusVariant = (status: string) => { + const s = status?.toLowerCase() || '' + if (['done', 'completed', 'closed', 'finalizado'].includes(s)) return 'secondary' + if (['in_progress', 'doing', 'wip', 'active', 'in progress', 'en progreso'].includes(s)) return 'default' + if (['blocked', 'bloqueado'].includes(s)) return 'destructive' + return 'outline' +} + +const statusLabel = (status: string) => { + const map: Record = { + backlog: 'Backlog', + todo: 'Por hacer', + in_progress: 'En progreso', + 'in progress': 'En progreso', + doing: 'Haciendo', + wip: 'WIP', + done: 'Hecho', + completed: 'Completado', + blocked: 'Bloqueado', + review: 'Revisión', + testing: 'Pruebas', + } + return map[status?.toLowerCase() || ''] || status || '—' +}