feat: version 2.17.2 -- Proyectos: selector Avance (Todos / Ocultar 100% / Solo 100%)
Reemplaza el checkbox "Ocultar proyectos 100%" para cubrir tambien "solo 100%" sin combinaciones contradictorias. Persistido en localStorage; migra el valor del checkbox anterior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,12 @@
|
|||||||
# Changelog - project.linkedcorp.net
|
# Changelog - project.linkedcorp.net
|
||||||
|
|
||||||
|
## [2.17.2] - 2026-10-20
|
||||||
|
### Changed
|
||||||
|
- Proyectos → listado: el checkbox "Ocultar proyectos 100%" pasa a ser el selector **Avance**
|
||||||
|
(Todos / Ocultar 100% / Solo 100%), así no hay combinaciones contradictorias. Arranca en
|
||||||
|
"Todos", se recuerda en el navegador aunque se cierre sesión, y respeta lo que ya estaba
|
||||||
|
marcado con el checkbox anterior.
|
||||||
|
|
||||||
## [2.17.1] - 2026-10-20
|
## [2.17.1] - 2026-10-20
|
||||||
### Added
|
### Added
|
||||||
- Proyectos → listado: checkbox "Ocultar proyectos 100%" (desmarcado por defecto). La elección
|
- Proyectos → listado: checkbox "Ocultar proyectos 100%" (desmarcado por defecto). La elección
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "project-linkedcorp-backend",
|
"name": "project-linkedcorp-backend",
|
||||||
"version": "2.17.1",
|
"version": "2.17.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"main": "src/server.js",
|
"main": "src/server.js",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "project-linkedcorp-frontend",
|
"name": "project-linkedcorp-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.17.1",
|
"version": "2.17.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -186,7 +186,9 @@ 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%',
|
project_filter_progress: 'Avance',
|
||||||
|
project_filter_progress_hide: 'Ocultar 100%',
|
||||||
|
project_filter_progress_only: 'Solo 100%',
|
||||||
|
|
||||||
nav_recurring_tasks: 'Tareas recurrentes',
|
nav_recurring_tasks: 'Tareas recurrentes',
|
||||||
nav_notes: 'Notas',
|
nav_notes: 'Notas',
|
||||||
@@ -669,7 +671,9 @@ 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',
|
project_filter_progress: 'Progress',
|
||||||
|
project_filter_progress_hide: 'Hide 100%',
|
||||||
|
project_filter_progress_only: 'Only 100%',
|
||||||
|
|
||||||
nav_recurring_tasks: 'Recurring tasks',
|
nav_recurring_tasks: 'Recurring tasks',
|
||||||
nav_notes: 'Notes',
|
nav_notes: 'Notes',
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ 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';
|
const PROGRESS_FILTER_KEY = 'plc_projects_progress_filter';
|
||||||
|
const LEGACY_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); }
|
||||||
@@ -49,13 +50,18 @@ 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.
|
// '' = todos, 'hide' = ocultar 100%, 'only' = solo 100%. Persistido en el navegador (sobrevive
|
||||||
const [hideCompleted, setHideCompleted] = useState(() => {
|
// al cierre de sesion). Respeta el checkbox anterior "Ocultar 100%" (clave vieja) si existia.
|
||||||
try { return localStorage.getItem(HIDE_COMPLETED_KEY) === '1'; } catch { return false; }
|
const [progressFilter, setProgressFilter] = useState(() => {
|
||||||
|
try {
|
||||||
|
const saved = localStorage.getItem(PROGRESS_FILTER_KEY);
|
||||||
|
if (saved !== null) return saved;
|
||||||
|
return localStorage.getItem(LEGACY_HIDE_COMPLETED_KEY) === '1' ? 'hide' : '';
|
||||||
|
} catch { return ''; }
|
||||||
});
|
});
|
||||||
function toggleHideCompleted(checked) {
|
function changeProgressFilter(value) {
|
||||||
setHideCompleted(checked);
|
setProgressFilter(value);
|
||||||
try { localStorage.setItem(HIDE_COMPLETED_KEY, checked ? '1' : '0'); } catch { /* sin storage: solo en memoria */ }
|
try { localStorage.setItem(PROGRESS_FILTER_KEY, value); } 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
|
||||||
@@ -194,9 +200,9 @@ export default function ProyectosPage() {
|
|||||||
return diffDays >= 0 && diffDays <= 7;
|
return diffDays >= 0 && diffDays <= 7;
|
||||||
})
|
})
|
||||||
: projects;
|
: projects;
|
||||||
const visibleProjects = hideCompleted && !showTrash
|
const visibleProjects = showTrash || !progressFilter
|
||||||
? dueSoonProjects.filter((p) => Number(p.progress_pct) < 100)
|
? dueSoonProjects
|
||||||
: dueSoonProjects;
|
: dueSoonProjects.filter((p) => (Number(p.progress_pct) >= 100) === (progressFilter === 'only'));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -239,6 +245,21 @@ export default function ProyectosPage() {
|
|||||||
<ComboBox options={[{ value: '', label: t('common_all') }, ...priorityOptions]} value={filterPriorityId} onChange={setFilterPriorityId} placeholder={t('common_priority')} />
|
<ComboBox options={[{ value: '', label: t('common_all') }, ...priorityOptions]} value={filterPriorityId} onChange={setFilterPriorityId} placeholder={t('common_priority')} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||||
|
<span className="text-muted" style={{ fontSize: '.72rem', whiteSpace: 'nowrap' }}>{t('project_filter_progress')}</span>
|
||||||
|
<div style={{ width: 160 }}>
|
||||||
|
<ComboBox
|
||||||
|
options={[
|
||||||
|
{ value: '', label: t('common_all') },
|
||||||
|
{ value: 'hide', label: t('project_filter_progress_hide') },
|
||||||
|
{ value: 'only', label: t('project_filter_progress_only') },
|
||||||
|
]}
|
||||||
|
value={progressFilter}
|
||||||
|
onChange={changeProgressFilter}
|
||||||
|
placeholder={t('project_filter_progress')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{canFilterByUser && (
|
{canFilterByUser && (
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||||
<span className="text-muted" style={{ fontSize: '.72rem', whiteSpace: 'nowrap' }}>Usuario</span>
|
<span className="text-muted" style={{ fontSize: '.72rem', whiteSpace: 'nowrap' }}>Usuario</span>
|
||||||
@@ -256,10 +277,6 @@ 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>
|
||||||
|
|||||||
Reference in New Issue
Block a user