ProjectListView + DashboardView: mostrar ID del proyecto (#305) junto al nombre
- pushDraft: épica usa JSON con client_taker + status=false - ToastNotification: sistema de notificaciones toast global - useToast: composable singleton para mostrar/descartar toasts
This commit is contained in:
+50
-39
@@ -11,6 +11,7 @@ import { Button } from '@/components/ui/button'
|
||||
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'
|
||||
@@ -36,7 +37,7 @@ const { t } = useI18n()
|
||||
const projects = useProjectsStore()
|
||||
const workItems = useWorkItemsStore()
|
||||
const usersStore = useUsersStore()
|
||||
|
||||
const { show: showToast } = useToast()
|
||||
const project = computed(() => projects.selected)
|
||||
|
||||
// ─── Team members for this project ────────────────────
|
||||
@@ -267,57 +268,64 @@ async function pushDraft(d: HuDraftRecord) {
|
||||
const token = localStorage.getItem('kappa_token')
|
||||
const headers = { 'Content-Type': 'application/json', ...(token ? { 'Authorization': `Bearer ${token}` } : {}) }
|
||||
|
||||
let endpoint: string, body: string
|
||||
|
||||
if (d.type === 'E') {
|
||||
// Push épica: buscar HUs vinculadas ya enviadas
|
||||
// Push épica
|
||||
const meta = JSON.parse(d.metadata || '{}')
|
||||
const linkedHuIds: number[] = []
|
||||
for (const huTitle of meta.linkedHuTitles || []) {
|
||||
const pushedHu = drafts.value.find(x => x.type !== 'E' && (x.title.toLowerCase().trim() === huTitle.toLowerCase().trim()) && x.kappaId)
|
||||
if (pushedHu?.kappaId) linkedHuIds.push(pushedHu.kappaId)
|
||||
}
|
||||
|
||||
const res = await fetch('/api/epicdevelopment/create/', {
|
||||
method: 'POST', headers,
|
||||
body: JSON.stringify({
|
||||
initiative: String(d.projectId), name: d.title,
|
||||
description: d.description ? `<p>${d.description.replace(/\n/g, '</p><p>')}</p>` : '',
|
||||
client_taker: null, hu: linkedHuIds,
|
||||
stimated_start_date: meta.estimatedStart || null,
|
||||
stimated_end_date: meta.estimatedEnd || null,
|
||||
}),
|
||||
endpoint = '/api/epicdevelopment/create/'
|
||||
body = JSON.stringify({
|
||||
initiative: String(d.projectId),
|
||||
name: d.title,
|
||||
description: d.description ? `<p>${d.description.replace(/\n/g, '</p><p>')}</p>` : '',
|
||||
stimated_start_date: meta.estimatedStart || null,
|
||||
stimated_end_date: meta.estimatedEnd || null,
|
||||
client_taker: Number(meta.clientTaker) || null,
|
||||
hu: linkedHuIds,
|
||||
status: false,
|
||||
})
|
||||
if (res.ok) {
|
||||
d.syncStatus = 'pushed'; await dbSaveDraft(d)
|
||||
} else {
|
||||
d.syncStatus = 'draft'; await dbSaveDraft(d)
|
||||
}
|
||||
} else {
|
||||
// Push HU individual
|
||||
const res = await fetch('/api/userstorys/create/', {
|
||||
method: 'POST', headers,
|
||||
body: JSON.stringify({
|
||||
initiative: String(d.projectId), title: d.title,
|
||||
description: d.description ? `<p>${d.description.replace(/\n/g, '</p><p>')}</p>` : '',
|
||||
criterios_aceptacion: d.acceptanceCriteria ? `<p>${d.acceptanceCriteria.replace(/\n/g, '</p><p>')}</p>` : '',
|
||||
story_points: '',
|
||||
priority: d.priority === 'Alta' ? '1' : d.priority === 'Baja' ? '3' : '2',
|
||||
sprint: '', asignado_a: [], client_taker: null,
|
||||
characterization_hu: '', has_impairment: false,
|
||||
epic_development: null, feature: '',
|
||||
initial_date: null, end_date: null,
|
||||
}),
|
||||
// Push HU
|
||||
endpoint = '/api/userstorys/create/'
|
||||
body = JSON.stringify({
|
||||
initiative: String(d.projectId), title: d.title,
|
||||
description: d.description ? `<p>${d.description.replace(/\n/g, '</p><p>')}</p>` : '',
|
||||
criterios_aceptacion: d.acceptanceCriteria ? `<p>${d.acceptanceCriteria.replace(/\n/g, '</p><p>')}</p>` : '',
|
||||
story_points: String(d.story_points ?? ''),
|
||||
priority: d.priority === 'Alta' ? '1' : d.priority === 'Baja' ? '3' : '2',
|
||||
sprint: '', asignado_a: [], client_taker: null,
|
||||
characterization_hu: '', has_impairment: false,
|
||||
epic_development: null, feature: '',
|
||||
initial_date: null, end_date: null,
|
||||
})
|
||||
if (res.ok) {
|
||||
}
|
||||
|
||||
const res = await fetch(endpoint, { method: 'POST', headers, body })
|
||||
if (res.ok) {
|
||||
if (d.type !== 'E') {
|
||||
const created = await res.json()
|
||||
d.kappaId = created.id || undefined
|
||||
d.syncStatus = 'pushed'
|
||||
await dbSaveDraft(d)
|
||||
} else {
|
||||
d.syncStatus = 'draft'; await dbSaveDraft(d)
|
||||
}
|
||||
d.syncStatus = 'pushed'
|
||||
await dbSaveDraft(d)
|
||||
showToast('success', d.type === 'E' ? 'Épica creada en KAPPA' : 'HU creada en KAPPA', d.title.slice(0, 100))
|
||||
} 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))
|
||||
d.syncStatus = 'draft'
|
||||
await dbSaveDraft(d)
|
||||
}
|
||||
} catch {
|
||||
d.syncStatus = 'draft'; await dbSaveDraft(d)
|
||||
} catch (e: any) {
|
||||
console.error('[Alpha] Error en pushDraft:', e)
|
||||
showToast('error', 'Error de red', e.message)
|
||||
d.syncStatus = 'draft'
|
||||
await dbSaveDraft(d)
|
||||
} finally {
|
||||
pushingDraftId.value = null
|
||||
await loadDrafts()
|
||||
@@ -420,7 +428,10 @@ const statusLabel = (status: unknown) => {
|
||||
<template>
|
||||
<div v-if="project" class="@container/main flex flex-1 flex-col gap-4 px-4 lg:px-6">
|
||||
<div class="flex flex-col gap-1">
|
||||
<h1 class="text-2xl font-bold tracking-tight">{{ project.name }}</h1>
|
||||
<h1 class="text-2xl font-bold tracking-tight">
|
||||
<span class="font-mono text-sm text-muted-foreground mr-2">#{{ project.id }}</span>
|
||||
{{ project.name }}
|
||||
</h1>
|
||||
<div class="flex items-center gap-2">
|
||||
<Badge v-if="project.key" variant="outline" class="text-xs">{{ project.key }}</Badge>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user