Fix: mapeo employee_id→user_id + status_name de KAPPA + filtro asignado solo desarrolladores asignados
- KappaUserStory: status_name, status/priority aceptan number - parseAssignedUser: separa employee_id (asignado_a) de user_id (assigned_to) employee_id se guarda negativo en Turso para distinguirlo - enrichHU: usa status_name de KAPPA directo, fallback a resolveStatusName - DashboardView: resolveEmployeeToUser() busca employee→user via employees store - assignedName: muestra nombre real desde employee→user, fallback asignado_a_names - Filtros: placeholder Estado/Prioridad/Asignado en vez de Todos - assignedUsers: filtro solo muestra desarrolladores asignados a HUs del proyecto
This commit is contained in:
+57
-29
@@ -51,21 +51,19 @@ const projectTeam = computed(() => {
|
||||
.map(u => ({ id: u!.id, name: u!.full_name || u!.email }))
|
||||
})
|
||||
|
||||
const allAssignableUsers = computed(() => {
|
||||
// Todos los usuarios activos + cualquier usuario asignado por KAPPA
|
||||
const assignedUsers = computed(() => {
|
||||
const seen = new Set<number>()
|
||||
const list: { id: number; name: string }[] = []
|
||||
for (const u of usersStore.activeUsers) {
|
||||
seen.add(u.id)
|
||||
list.push({ id: u.id, name: u.full_name || u.email })
|
||||
}
|
||||
// Incluir usuarios asignados por KAPPA aunque no estén en activeUsers
|
||||
for (const hu of workItems.userStories) {
|
||||
const uid = hu._assignedUserId
|
||||
if (uid != null && !seen.has(uid)) {
|
||||
seen.add(uid)
|
||||
list.push({ id: uid, name: hu._assignedName || `Usuario #${uid}` })
|
||||
}
|
||||
const employeeId = hu._assignedEmployeeId
|
||||
if (employeeId == null || employeeId <= 0 || seen.has(employeeId)) continue
|
||||
seen.add(employeeId)
|
||||
// Resolver employee → user para mostrar el nombre real
|
||||
const uid = resolveEmployeeToUser(employeeId)
|
||||
const name = uid != null
|
||||
? (usersStore.users.find(u => u.id === uid)?.full_name || usersStore.users.find(u => u.id === uid)?.email || '')
|
||||
: ''
|
||||
list.push({ id: employeeId, name: name || hu._assignedName || `Usuario #${employeeId}` })
|
||||
}
|
||||
return list.sort((a, b) => a.name.localeCompare(b.name))
|
||||
})
|
||||
@@ -87,10 +85,21 @@ function saveAssignment(huId: number, userId: number | null) {
|
||||
storage.setJSON(STORAGE_KEY, all)
|
||||
}
|
||||
|
||||
function getAssignedUserId(hu: { id?: number; _assignedUserId?: number | null }): number | null {
|
||||
// 1. KAPPA asigna directo
|
||||
function resolveEmployeeToUser(employeeId: number | null): number | null {
|
||||
if (employeeId == null) return null
|
||||
const emp = usersStore.employees.find(e => e.id === employeeId)
|
||||
return emp?.user ?? null
|
||||
}
|
||||
|
||||
function getAssignedUserId(hu: { _assignedEmployeeId?: number | null; _assignedUserId?: number | null; id?: number }): number | null {
|
||||
// 1. KAPPA asigna por employee_id (asignado_a: [1135]) → resolver a user_id
|
||||
if (hu._assignedEmployeeId != null && hu._assignedEmployeeId > 0) {
|
||||
const userId = resolveEmployeeToUser(hu._assignedEmployeeId)
|
||||
if (userId != null) return userId
|
||||
}
|
||||
// 2. KAPPA asigna directo por user_id (assigned_to)
|
||||
if (hu._assignedUserId != null && hu._assignedUserId > 0) return hu._assignedUserId
|
||||
// 2. Fallback: asignación manual en localStorage
|
||||
// 3. Fallback: asignación manual en localStorage
|
||||
if (hu.id != null) {
|
||||
const all = loadAssignments()
|
||||
return all[hu.id] ?? null
|
||||
@@ -98,11 +107,30 @@ function getAssignedUserId(hu: { id?: number; _assignedUserId?: number | null })
|
||||
return null
|
||||
}
|
||||
|
||||
function assignedName(hu: { id?: number; _assignedUserId?: number | null; _assignedName?: string }): string {
|
||||
function assignedName(hu: { _assignedName?: string; _assignedEmployeeId?: number | null; _assignedUserId?: number | null; id?: number }): string {
|
||||
// 1. Intentar resolver employee_id → user_id → nombre real
|
||||
if (hu._assignedEmployeeId != null && hu._assignedEmployeeId > 0) {
|
||||
const userId = resolveEmployeeToUser(hu._assignedEmployeeId)
|
||||
if (userId != null) {
|
||||
const u = usersStore.users.find(u => u.id === userId)
|
||||
if (u) return u.full_name || u.email
|
||||
}
|
||||
// Si el employee no se ha cargado aún, mostrar el nombre de KAPPA (asignado_a_names)
|
||||
if (hu._assignedName) return hu._assignedName
|
||||
}
|
||||
// 2. user_id directo
|
||||
if (hu._assignedUserId != null && hu._assignedUserId > 0) {
|
||||
const u = usersStore.users.find(u => u.id === hu._assignedUserId)
|
||||
if (u) return u.full_name || u.email
|
||||
if (hu._assignedName) return hu._assignedName
|
||||
}
|
||||
// 3. Fallback localStorage
|
||||
const uid = getAssignedUserId(hu)
|
||||
if (!uid) return ''
|
||||
const u = usersStore.users.find(u => u.id === uid)
|
||||
return u?.full_name || u?.email || hu._assignedName || ''
|
||||
if (uid) {
|
||||
const u = usersStore.users.find(u => u.id === uid)
|
||||
if (u) return u.full_name || u.email
|
||||
}
|
||||
return hu._assignedName || ''
|
||||
}
|
||||
|
||||
// ─── Priority helpers ─────────────────────────────────
|
||||
@@ -132,30 +160,30 @@ function priorityLabel(p: unknown) {
|
||||
}
|
||||
|
||||
// ─── Filters ─────────────────────────────────────────
|
||||
const filterStatus = ref('__all')
|
||||
const filterPriority = ref('__all')
|
||||
const filterAssigned = ref('__all')
|
||||
const filterStatus = ref('')
|
||||
const filterPriority = ref('')
|
||||
const filterAssigned = ref('')
|
||||
|
||||
const filteredHUs = computed(() => {
|
||||
let list = workItems.userStories
|
||||
if (filterStatus.value !== '__all') {
|
||||
if (filterStatus.value && filterStatus.value !== '__all') {
|
||||
list = list.filter(h => {
|
||||
const s = String(h.status ?? '').toLowerCase()
|
||||
return s === filterStatus.value
|
||||
})
|
||||
}
|
||||
if (filterPriority.value !== '__all') {
|
||||
if (filterPriority.value && filterPriority.value !== '__all') {
|
||||
list = list.filter(h => {
|
||||
const p = String(h.priority ?? '').toLowerCase()
|
||||
return p === filterPriority.value
|
||||
})
|
||||
}
|
||||
if (filterAssigned.value !== '__all') {
|
||||
if (filterAssigned.value && filterAssigned.value !== '__all') {
|
||||
if (filterAssigned.value === '__none') {
|
||||
list = list.filter(h => !getAssignedUserId(h))
|
||||
list = list.filter(h => !getAssignedUserId(h) && !h._assignedEmployeeId)
|
||||
} else {
|
||||
const uid = Number(filterAssigned.value)
|
||||
list = list.filter(h => getAssignedUserId(h) === uid)
|
||||
const targetId = Number(filterAssigned.value)
|
||||
list = list.filter(h => h._assignedEmployeeId === targetId || getAssignedUserId(h) === targetId)
|
||||
}
|
||||
}
|
||||
return list
|
||||
@@ -674,7 +702,7 @@ const statusLabel = (status: unknown) => {
|
||||
<SelectContent>
|
||||
<SelectItem value="__all" class="text-xs">{{ t('dashboard.filterAll') }}</SelectItem>
|
||||
<SelectItem value="__none" class="text-xs">{{ t('dashboard.unassigned') }}</SelectItem>
|
||||
<SelectItem v-for="m in allAssignableUsers" :key="m.id" :value="String(m.id)" class="text-xs">{{ m.name }}</SelectItem>
|
||||
<SelectItem v-for="m in assignedUsers" :key="m.id" :value="String(m.id)" class="text-xs">{{ m.name }}</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user