diff --git a/src/stores/workitems.ts b/src/stores/workitems.ts index b5d5f5e..bc5b173 100644 --- a/src/stores/workitems.ts +++ b/src/stores/workitems.ts @@ -89,7 +89,7 @@ export const useWorkItemsStore = defineStore('workitems', () => { return { id: null, name: '', employeeId: null } } - function enrichHU(hu: { title?: string; id?: number; status?: string | number | null; status_name?: string | null; priority?: string | number | null; story_points?: number | null; acceptance_criteria?: string | null; criterios_aceptacion?: string | null; assigned_to?: number | null; asignado_a?: number[] | string[] | null; asignado_a_names?: string[] | string | null; assigned_name?: string }, initiativeId: number): EnrichedUserStory { + function enrichHU(hu: { title?: string; id?: number; description?: string | null; status?: string | number | null; status_name?: string | null; priority?: string | number | null; story_points?: number | null; acceptance_criteria?: string | null; criterios_aceptacion?: string | null; assigned_to?: number | null; asignado_a?: number[] | string[] | null; asignado_a_names?: string[] | string | null; assigned_name?: string }, initiativeId: number): EnrichedUserStory { const h = parseHierarchy(hu.title || '') const rawCriteria = hu.acceptance_criteria || hu.criterios_aceptacion || '' const criteriaList = rawCriteria ? parseQuillList(rawCriteria) : [] @@ -100,6 +100,7 @@ export const useWorkItemsStore = defineStore('workitems', () => { status: String(hu.status ?? ''), priority: String(hu.priority ?? ''), story_points: hu.story_points ?? undefined, + description: hu.description || '', acceptance_criteria: rawCriteria, criterios_aceptacion: rawCriteria, initiative: initiativeId, diff --git a/src/views/DashboardView.vue b/src/views/DashboardView.vue index 7fa399f..110fbd9 100644 --- a/src/views/DashboardView.vue +++ b/src/views/DashboardView.vue @@ -6,12 +6,12 @@ import { useWorkItemsStore } from '@/stores/workitems' import { useUsersStore } from '@/stores/users' import { storage } from '@/services/storage' import { getTypeLabel, getTypeColor, getTypeIcon } from '@/services/hierarchy' -import { Activity, FileText, Layers, Clock, Info, AlertTriangle, Plus, Brain, Sparkles, Loader2, CheckCircle2, XCircle, Send, ChevronDown } from 'lucide-vue-next' +import { Activity, FileText, Layers, Clock, Info, AlertTriangle, Plus, Brain, Sparkles, Loader2, CheckCircle2, XCircle, Send, ChevronDown, Eye } from 'lucide-vue-next' import { Button } from '@/components/ui/button' +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog' import HuDrafts from '@/components/HuDrafts.vue' import AiProjectChat from '@/components/AiProjectChat.vue' import { analyzeProject, saveAsDrafts } from '@/services/project-analyzer' -import { useToast } from '@/composables/useToast' import { getDrafts, deleteDraft, type HuDraftRecord } from '@/services/hu-drafts-db' import { kappa } from '@/services/kappa-api' import { generateAndSavePlan, getQAPlans, type HUQAPlan } from '@/services/qa-analyzer' @@ -37,9 +37,27 @@ const { t } = useI18n() const projects = useProjectsStore() const workItems = useWorkItemsStore() const usersStore = useUsersStore() -const { show: showToast } = useToast() const project = computed(() => projects.selected) +// ─── Inline notification (funciona en Tauri) ───────── +const notification = ref<{ type: 'success' | 'error'; message: string } | null>(null) +let notifTimeout: ReturnType | null = null + +function showNotif(type: 'success' | 'error', message: string) { + if (notifTimeout) clearTimeout(notifTimeout) + notification.value = { type, message } + notifTimeout = setTimeout(() => { notification.value = null }, 5000) +} + +// ─── Description modals ────────────────────────────── +const descModal = ref<{ title: string; content: string } | null>(null) +const descModalOpen = ref(false) + +function openDescription(title: string, content: string) { + descModal.value = { title, content } + descModalOpen.value = true +} + // ─── Team members for this project ──────────────────── const projectTeam = computed(() => { const p = project.value @@ -311,19 +329,20 @@ async function pushDraft(d: HuDraftRecord) { const created = await res.json() d.kappaId = created.id || undefined } - d.syncStatus = 'pushed' - await dbSaveDraft(d) - showToast('success', d.type === 'E' ? 'Épica creada en KAPPA' : 'HU creada en KAPPA', d.title.slice(0, 100)) + await deleteDraft(d.id) + await loadDrafts() + await workItems.fetchWorkItems(project.value!.id) + showNotif('success', `${d.type === 'E' ? 'Épica' : 'HU'} creada en KAPPA: ${d.title.slice(0, 80)}`) } else { const errorText = await res.text().catch(() => 'Error desconocido') console.error(`[Alpha] Error push a KAPPA (${endpoint}): ${res.status} — ${errorText}`) - showToast('error', 'Error al crear en KAPPA', errorText.slice(0, 300)) + showNotif('error', `Error (${res.status}): ${errorText.slice(0, 200)}`) d.syncStatus = 'draft' await dbSaveDraft(d) } } catch (e: any) { console.error('[Alpha] Error en pushDraft:', e) - showToast('error', 'Error de red', e.message) + showNotif('error', `Error de red: ${e.message}`) d.syncStatus = 'draft' await dbSaveDraft(d) } finally { @@ -605,40 +624,49 @@ const statusLabel = (status: unknown) => { - - + + + + {{ t('dashboard.epicsCount', { count: workItems.totalEpics }) }} + + + + + + {{ t('dashboard.code') }} + {{ t('users.role') }} + {{ t('dashboard.title') }} + Desc + {{ t('dashboard.assignedTo') }} + {{ t('dashboard.status') }} + + + + + {{ epic.code || `EP-${epic.id}` }} + + {{ getTypeLabel(epic._itemType) }} + + {{ epic._cleanName || epic.name || epic.title || t('dashboard.epicFallback', { id: epic.id }) }} + + + + + + + + + + + {{ statusLabel(epic.status || '') }} + + + +
+
+
@@ -727,6 +755,7 @@ const statusLabel = (status: unknown) => { {{ t('dashboard.code') }} {{ t('users.role') }} {{ t('dashboard.title') }} + Desc SP {{ t('dashboard.status') }} {{ t('dashboard.priority') }} @@ -750,6 +779,12 @@ const statusLabel = (status: unknown) => { + + + + {{ hu.story_points ?? '—' }} {{ hu._statusName || statusLabel(hu.status || '') }} {{ priorityLabel(hu.priority) }} @@ -763,6 +798,31 @@ const statusLabel = (status: unknown) => {

{{ t('dashboard.noUserStories') }}

+ + + + + + {{ descModal?.title }} + +
+
+
+ + +
+ + +
+

{{ notification.type === 'success' ? 'Completado' : 'Error' }}

+

{{ notification.message }}

+
+ +
diff --git a/src/views/NewDashboardView.vue b/src/views/NewDashboardView.vue index 732976f..e82240b 100644 --- a/src/views/NewDashboardView.vue +++ b/src/views/NewDashboardView.vue @@ -10,7 +10,6 @@ import ProjectListView from "@/views/ProjectListView.vue" import UsersView from "@/views/UsersView.vue" import TranscriptionsView from "@/views/TranscriptionsView.vue" import SettingsView from "@/views/SettingsView.vue" -import ToastNotification from "@/components/ToastNotification.vue" const { t } = useI18n() @@ -172,6 +171,5 @@ const tabContent: Record
-