feat: version 2.17.1 -- Proyectos: checkbox "Ocultar proyectos 100%"

Desmarcado por defecto; la eleccion se guarda en localStorage y sobrevive al
cierre de sesion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Milton Gonzalez
2026-10-20 14:57:12 -05:00
parent 30bb546b84
commit a488965450
6 changed files with 27 additions and 4 deletions
+5
View File
@@ -1,5 +1,10 @@
# Changelog - project.linkedcorp.net # Changelog - project.linkedcorp.net
## [2.17.1] - 2026-10-20
### Added
- Proyectos → listado: checkbox "Ocultar proyectos 100%" (desmarcado por defecto). La elección
se recuerda en el navegador, aunque se cierre sesión.
## [2.17.0] - 2026-10-20 ## [2.17.0] - 2026-10-20
### Added ### Added
- Equipos → detalle: pestaña **Usuarios** (después de General) con el usuario que tiene sesión - Equipos → detalle: pestaña **Usuarios** (después de General) con el usuario que tiene sesión
+1 -1
View File
@@ -1 +1 @@
2.17.0 2.17.1
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "project-linkedcorp-backend", "name": "project-linkedcorp-backend",
"version": "2.17.0", "version": "2.17.1",
"private": true, "private": true,
"type": "module", "type": "module",
"main": "src/server.js", "main": "src/server.js",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "project-linkedcorp-frontend", "name": "project-linkedcorp-frontend",
"private": true, "private": true,
"version": "2.17.0", "version": "2.17.1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
+2
View File
@@ -186,6 +186,7 @@ export const messages = {
project_updated_at: 'Actualizado', project_updated_at: 'Actualizado',
project_deleted_at: 'Eliminado', project_deleted_at: 'Eliminado',
project_filter_due_soon: 'Solo próximos a vencer (7 días)', project_filter_due_soon: 'Solo próximos a vencer (7 días)',
project_filter_hide_completed: 'Ocultar proyectos 100%',
nav_recurring_tasks: 'Tareas recurrentes', nav_recurring_tasks: 'Tareas recurrentes',
nav_notes: 'Notas', nav_notes: 'Notas',
@@ -668,6 +669,7 @@ export const messages = {
project_updated_at: 'Updated', project_updated_at: 'Updated',
project_deleted_at: 'Deleted', project_deleted_at: 'Deleted',
project_filter_due_soon: 'Due soon only (7 days)', project_filter_due_soon: 'Due soon only (7 days)',
project_filter_hide_completed: 'Hide 100% projects',
nav_recurring_tasks: 'Recurring tasks', nav_recurring_tasks: 'Recurring tasks',
nav_notes: 'Notes', nav_notes: 'Notes',
+17 -1
View File
@@ -22,6 +22,7 @@ import { DetailPopup } from '../../components/DetailPopup.jsx';
import { SharedWithIcon } from '../../components/SharedWithIcon.jsx'; import { SharedWithIcon } from '../../components/SharedWithIcon.jsx';
const CAN_DELETE_ROLES = ['superadmin', 'admin', 'it_manager', 'project_lead']; const CAN_DELETE_ROLES = ['superadmin', 'admin', 'it_manager', 'project_lead'];
const HIDE_COMPLETED_KEY = 'plc_projects_hide_completed';
function flatten(nodes, acc = []) { function flatten(nodes, acc = []) {
for (const n of nodes) { acc.push(n); if (n.children?.length) flatten(n.children, acc); } for (const n of nodes) { acc.push(n); if (n.children?.length) flatten(n.children, acc); }
@@ -48,6 +49,14 @@ export default function ProyectosPage() {
const [filterStatusId, setFilterStatusId] = useState(''); const [filterStatusId, setFilterStatusId] = useState('');
const [filterPriorityId, setFilterPriorityId] = useState(''); const [filterPriorityId, setFilterPriorityId] = useState('');
const [filterDueSoon, setFilterDueSoon] = useState(false); const [filterDueSoon, setFilterDueSoon] = useState(false);
// Persistido en el navegador: se conserva al cerrar sesion o recargar.
const [hideCompleted, setHideCompleted] = useState(() => {
try { return localStorage.getItem(HIDE_COMPLETED_KEY) === '1'; } catch { return false; }
});
function toggleHideCompleted(checked) {
setHideCompleted(checked);
try { localStorage.setItem(HIDE_COMPLETED_KEY, checked ? '1' : '0'); } catch { /* sin storage: solo en memoria */ }
}
const [filterOwnerUserId, setFilterOwnerUserId] = useState(''); const [filterOwnerUserId, setFilterOwnerUserId] = useState('');
// Prueba exploratoria: filtro "ver todos / por usuario" solo para roles que ya ven todos los // Prueba exploratoria: filtro "ver todos / por usuario" solo para roles que ya ven todos los
// proyectos hoy (superadmin/admin/it_manager) -- backend ya soporta ownerUserId, sin cambios. // proyectos hoy (superadmin/admin/it_manager) -- backend ya soporta ownerUserId, sin cambios.
@@ -178,13 +187,16 @@ export default function ProyectosPage() {
if (!projects) return <div className="text-muted">{t('common_loading')}</div>; if (!projects) return <div className="text-muted">{t('common_loading')}</div>;
const visibleProjects = filterDueSoon && !showTrash const dueSoonProjects = filterDueSoon && !showTrash
? projects.filter((p) => { ? projects.filter((p) => {
if (p.status_is_closed || !p.estimated_end_date) return false; if (p.status_is_closed || !p.estimated_end_date) return false;
const diffDays = Math.round((new Date(p.estimated_end_date) - new Date()) / 86400000); const diffDays = Math.round((new Date(p.estimated_end_date) - new Date()) / 86400000);
return diffDays >= 0 && diffDays <= 7; return diffDays >= 0 && diffDays <= 7;
}) })
: projects; : projects;
const visibleProjects = hideCompleted && !showTrash
? dueSoonProjects.filter((p) => Number(p.progress_pct) < 100)
: dueSoonProjects;
return ( return (
<div> <div>
@@ -244,6 +256,10 @@ export default function ProyectosPage() {
<input type="checkbox" checked={filterDueSoon} onChange={(e) => setFilterDueSoon(e.target.checked)} /> <input type="checkbox" checked={filterDueSoon} onChange={(e) => setFilterDueSoon(e.target.checked)} />
{t('project_filter_due_soon')} {t('project_filter_due_soon')}
</label> </label>
<label className="checkbox-row">
<input type="checkbox" checked={hideCompleted} onChange={(e) => toggleHideCompleted(e.target.checked)} />
{t('project_filter_hide_completed')}
</label>
</> </>
)} )}
</div> </div>