From d44f96bb6c302b39c77da7d333bc6029fae8e674 Mon Sep 17 00:00:00 2001 From: Milton Gonzalez Date: Wed, 14 Oct 2026 11:53:43 -0500 Subject: [PATCH] =?UTF-8?q?fix:=20version=202.11.1=20--=20mueve=20los=20co?= =?UTF-8?q?ntadores=20de=202.11.0=20de=20columnas=20de=20grilla=20a=20badg?= =?UTF-8?q?es=20de=20pesta=C3=B1a?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La 2.11.0 agrego los contadores de dependencias/comentarios/documentos/miembros como columnas nuevas en las tablas de Proyectos y Actividades -- no era el pedido original, desbordaba la grilla. Se revierten esas columnas (y el componente CountBadge que solo ellas usaban) y los contadores van donde correspondia desde el principio: como badge junto al nombre de cada pestaña, al mismo estilo que ya usaba "Tareas n/n" (componente Tabs + .tab-badge): - Proyecto: pestañas Miembros, Actividades (completas/total), Comentarios, Documentos. - Actividad: pestaña Dependencias (ya existia Tareas/Comentarios/Documentos, solo faltaba esta). De paso: Tabs.jsx ocultaba el badge cuando count era 0 (!!tab.count) -- se cambia a mostrar siempre que la pestaña mande la prop (count !== undefined), para que 0 se vea como "0" y no desaparezca. CommentsPanel/AttachmentsPanel ganan un onChanged opcional para que el contador de Comentarios/Documentos del PROYECTO se actualice al tiro sin tener que recargar la pagina (el de la actividad ya se refrescaba solo al cambiar de pestaña). El backend de 2.11.0 (subconsultas dependencies_count/comments_count/documents_count/ members_count/activities_total/activities_complete en los LIST_SELECT) se mantiene igual, solo cambia donde el frontend los usa. Co-Authored-By: Claude Sonnet 5 --- CHANGELOG.md | 9 +++++++++ VERSION | 2 +- backend/package.json | 2 +- frontend/package.json | 2 +- frontend/src/components/AttachmentsPanel.jsx | 5 +++-- frontend/src/components/CommentsPanel.jsx | 3 ++- frontend/src/components/CountBadge.jsx | 11 ----------- frontend/src/components/Tabs.jsx | 4 +++- frontend/src/pages/Proyectos/ActivityDetailPanel.jsx | 2 +- .../src/pages/Proyectos/ProjectActivitiesTab.jsx | 6 +----- frontend/src/pages/Proyectos/ProyectoDetallePage.jsx | 12 ++++++------ frontend/src/pages/Proyectos/ProyectosPage.jsx | 9 +-------- frontend/src/styles/app.css | 2 -- 13 files changed, 29 insertions(+), 40 deletions(-) delete mode 100644 frontend/src/components/CountBadge.jsx diff --git a/CHANGELOG.md b/CHANGELOG.md index d3f0801..a208b77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog - project.linkedcorp.net +## [2.11.1] - 2026-10-14 +### Fixed +- La 2.11.0 puso los contadores de dependencias/comentarios/documentos/miembros como columnas + nuevas en las grillas de Proyectos y Actividades — no era lo pedido, desbordaba la tabla. + Se quitan esas columnas y los contadores van donde correspondía: como badge junto al nombre + de cada pestaña (Miembros, Actividades, Comentarios, Documentos del proyecto; Dependencias, + Comentarios, Documentos de la actividad), al mismo estilo que ya usaba "Tareas n/n". De paso + se corrige que el badge de una pestaña se ocultaba en 0 en vez de mostrarlo. + ## [2.11.0] - 2026-10-14 ### Added - Listado de Actividades (dentro de un proyecto): columnas nuevas con el número de diff --git a/VERSION b/VERSION index 46b81d8..6ceb272 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.11.0 +2.11.1 diff --git a/backend/package.json b/backend/package.json index 50cd47f..65a74f3 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "project-linkedcorp-backend", - "version": "2.11.0", + "version": "2.11.1", "private": true, "type": "module", "main": "src/server.js", diff --git a/frontend/package.json b/frontend/package.json index ba6d4af..b066749 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "project-linkedcorp-frontend", "private": true, - "version": "2.11.0", + "version": "2.11.1", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/components/AttachmentsPanel.jsx b/frontend/src/components/AttachmentsPanel.jsx index 99f6b6c..49e9b06 100644 --- a/frontend/src/components/AttachmentsPanel.jsx +++ b/frontend/src/components/AttachmentsPanel.jsx @@ -13,7 +13,7 @@ import hljsDark from 'highlight.js/styles/vs2015.css?inline'; const VIEWABLE_MIME = new Set(['text/plain', 'text/markdown']); -export function AttachmentsPanel({ entityType, entityId }) { +export function AttachmentsPanel({ entityType, entityId, onChanged }) { const { t, openDialog, theme } = useUi(); const runAction = useAction(); const { data: files, reload } = useAsync(() => listAttachments(entityType, entityId), [entityType, entityId]); @@ -41,6 +41,7 @@ export function AttachmentsPanel({ entityType, entityId }) { await runAction(async () => { await uploadAttachment(entityType, entityId, file); await reload(); + onChanged?.(); // refresca el contador de la pestaña "Documentos" en el padre }); e.target.value = ''; } @@ -52,7 +53,7 @@ export function AttachmentsPanel({ entityType, entityId }) { message: t('common_confirm_delete_msg'), actions: [ { label: t('common_cancel'), variant: 'standard' }, - { label: t('common_delete'), variant: 'danger', onClick: () => runAction(async () => { await deleteAttachment(file.id); await reload(); }) }, + { label: t('common_delete'), variant: 'danger', onClick: () => runAction(async () => { await deleteAttachment(file.id); await reload(); onChanged?.(); }) }, ], }); } diff --git a/frontend/src/components/CommentsPanel.jsx b/frontend/src/components/CommentsPanel.jsx index 0a4e9e6..f24f6d2 100644 --- a/frontend/src/components/CommentsPanel.jsx +++ b/frontend/src/components/CommentsPanel.jsx @@ -5,7 +5,7 @@ import { useAsync, useAction } from '../hooks/useAsync.js'; import { listComments, createComment } from '../services/comments.js'; import { Button } from './Button.jsx'; -export function CommentsPanel({ entityType, entityId }) { +export function CommentsPanel({ entityType, entityId, onChanged }) { const { t } = useUi(); const runAction = useAction(); const { data: comments, reload } = useAsync(() => listComments(entityType, entityId), [entityType, entityId]); @@ -17,6 +17,7 @@ export function CommentsPanel({ entityType, entityId }) { await createComment(entityType, entityId, message.trim()); setMessage(''); await reload(); + onChanged?.(); // refresca el contador de la pestaña "Comentarios" en el padre }); } diff --git a/frontend/src/components/CountBadge.jsx b/frontend/src/components/CountBadge.jsx deleted file mode 100644 index c264c18..0000000 --- a/frontend/src/components/CountBadge.jsx +++ /dev/null @@ -1,11 +0,0 @@ -// Contador chico con icono para columnas de listado (dependencias/comentarios/documentos/ -// miembros). Siempre muestra el numero, incluido 0 -- a diferencia de SharedWithIcon/Tabs que -// ocultan el badge en 0, aca el pedido es que el contador siempre sea visible. -export function CountBadge({ icon: Icon, count, title }) { - return ( - - - {count} - - ); -} diff --git a/frontend/src/components/Tabs.jsx b/frontend/src/components/Tabs.jsx index 5c6182d..98497aa 100644 --- a/frontend/src/components/Tabs.jsx +++ b/frontend/src/components/Tabs.jsx @@ -4,7 +4,9 @@ export function Tabs({ tabs, active, onChange }) { {tabs.map((tab) => ( ))} diff --git a/frontend/src/pages/Proyectos/ActivityDetailPanel.jsx b/frontend/src/pages/Proyectos/ActivityDetailPanel.jsx index 1b6bc8d..d393f63 100644 --- a/frontend/src/pages/Proyectos/ActivityDetailPanel.jsx +++ b/frontend/src/pages/Proyectos/ActivityDetailPanel.jsx @@ -153,7 +153,7 @@ export default function ActivityDetailPanel({ activity, projectId, siblingActivi tabs={[ { key: 'detail', label: t('tab_info') }, { key: 'tasks', label: t('tasks_title'), count: tasksTabCount }, - { key: 'dependencies', label: t('activity_dependencies') }, + { key: 'dependencies', label: t('activity_dependencies'), count: (activity.dependencies || []).length }, { key: 'comments', label: t('tab_comments'), count: (comments || []).length }, { key: 'documents', label: t('tab_documents'), count: (attachments || []).length }, ]} diff --git a/frontend/src/pages/Proyectos/ProjectActivitiesTab.jsx b/frontend/src/pages/Proyectos/ProjectActivitiesTab.jsx index e89a0d4..14fafec 100644 --- a/frontend/src/pages/Proyectos/ProjectActivitiesTab.jsx +++ b/frontend/src/pages/Proyectos/ProjectActivitiesTab.jsx @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Plus, Save, Trash2, ArrowRightLeft, FolderUp, Archive, RotateCcw, Link2, MessageSquare, Paperclip } from 'lucide-react'; +import { Plus, Save, Trash2, ArrowRightLeft, FolderUp, Archive, RotateCcw } from 'lucide-react'; import { useUi } from '../../context/ui-context.jsx'; import { useAuth } from '../../context/auth-context.jsx'; import { useAsync, useAction } from '../../hooks/useAsync.js'; @@ -19,7 +19,6 @@ import { ComboBox } from '../../components/ComboBox.jsx'; import { StatusBadge, ProgressBar, DueBadge } from '../../components/StatusBadge.jsx'; import { dueStatus } from '../../utils/dueStatus.js'; import { DetailPopup } from '../../components/DetailPopup.jsx'; -import { CountBadge } from '../../components/CountBadge.jsx'; import ActivityDetailPanel from './ActivityDetailPanel.jsx'; const EMPTY_FORM = { name: '', description: '', responsibleUserId: '', priorityId: '', statusId: '', startDate: '', dueDate: '', isMilestone: false }; @@ -213,9 +212,6 @@ export default function ProjectActivitiesTab({ project, projectId, openActivityI ) }, { key: 'progress_pct', label: t('activity_progress'), render: (r) =>
}, - { key: 'dependencies_count', label: t('activity_dependencies'), render: (r) => }, - { key: 'comments_count', label: t('tab_comments'), render: (r) => }, - { key: 'documents_count', label: t('tab_documents'), render: (r) => }, { key: 'updated_at', label: t('activity_updated_at'), render: (r) => {String(r.updated_at).slice(0, 16)} }, ]; diff --git a/frontend/src/pages/Proyectos/ProyectoDetallePage.jsx b/frontend/src/pages/Proyectos/ProyectoDetallePage.jsx index 8bcae8f..081339a 100644 --- a/frontend/src/pages/Proyectos/ProyectoDetallePage.jsx +++ b/frontend/src/pages/Proyectos/ProyectoDetallePage.jsx @@ -44,12 +44,12 @@ export default function ProyectoDetallePage() { } {tab === 'calendar' && } - {tab === 'comments' && } - {tab === 'documents' && } + {tab === 'comments' && } + {tab === 'documents' && } ); } diff --git a/frontend/src/pages/Proyectos/ProyectosPage.jsx b/frontend/src/pages/Proyectos/ProyectosPage.jsx index 256f773..a0a92b1 100644 --- a/frontend/src/pages/Proyectos/ProyectosPage.jsx +++ b/frontend/src/pages/Proyectos/ProyectosPage.jsx @@ -1,6 +1,6 @@ import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; -import { Plus, Save, Trash2, RotateCcw, ArrowLeft, Users, ListChecks, MessageSquare, Paperclip } from 'lucide-react'; +import { Plus, Save, Trash2, RotateCcw, ArrowLeft } from 'lucide-react'; import { useUi } from '../../context/ui-context.jsx'; import { useAuth } from '../../context/auth-context.jsx'; import { useAsync, useAction } from '../../hooks/useAsync.js'; @@ -20,7 +20,6 @@ import { StatusBadge, ProgressBar } from '../../components/StatusBadge.jsx'; import { Badge } from '../../components/Badge.jsx'; import { DetailPopup } from '../../components/DetailPopup.jsx'; import { SharedWithIcon } from '../../components/SharedWithIcon.jsx'; -import { CountBadge } from '../../components/CountBadge.jsx'; const CAN_DELETE_ROLES = ['superadmin', 'admin', 'it_manager', 'project_lead']; @@ -170,13 +169,7 @@ export default function ProyectosPage() { { key: 'status_name', label: t('common_status'), render: (r) => }, { key: 'priority_name', label: t('common_priority'), sortValue: (r) => r.priority_level, render: (r) => }, { key: 'owner_name', label: t('project_owner') }, - { key: 'members_count', label: t('project_members'), render: (r) => }, { key: 'progress_pct', label: t('project_progress'), render: (r) =>
}, - { key: 'activities_progress', label: t('tab_activities'), sortValue: (r) => (r.activities_total ? r.activities_complete / r.activities_total : 0), render: (r) => ( - {r.activities_complete}/{r.activities_total} - ) }, - { key: 'comments_count', label: t('tab_comments'), render: (r) => }, - { key: 'documents_count', label: t('tab_documents'), render: (r) => }, { key: 'shared', label: '', sortable: false, render: (r) => }, { key: 'risk_level', label: t('project_risk'), render: (r) => {t(`risk_${r.risk_level}`)} }, { key: 'updated_at', label: t('project_updated_at'), render: (r) => String(r.updated_at).slice(0, 16) }, diff --git a/frontend/src/styles/app.css b/frontend/src/styles/app.css index b5e2118..96a7b96 100644 --- a/frontend/src/styles/app.css +++ b/frontend/src/styles/app.css @@ -229,8 +229,6 @@ table.list-table { width: 100%; border-collapse: collapse; font-size: .8rem; } background: rgb(var(--danger) / .18); color: rgb(var(--danger)); font-size: .68rem; font-weight: 700; line-height: 1; } -.count-badge { display: inline-flex; align-items: center; gap: 4px; color: rgb(var(--muted)); font-size: .8rem; white-space: nowrap; } - /* --- Cards / KPIs --- */ .kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 14px; margin-bottom: 20px; } .kpi-card { background: rgb(var(--surface)); border: 1px solid rgb(var(--line)); border-radius: var(--r-lg); padding: 16px; }