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
|
||||
|
||||
## [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
|
||||
### Added
|
||||
- Proyectos → listado: checkbox "Ocultar proyectos 100%" (desmarcado por defecto). La elección
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "project-linkedcorp-backend",
|
||||
"version": "2.17.1",
|
||||
"version": "2.17.2",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"main": "src/server.js",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "project-linkedcorp-frontend",
|
||||
"private": true,
|
||||
"version": "2.17.1",
|
||||
"version": "2.17.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -186,7 +186,9 @@ export const messages = {
|
||||
project_updated_at: 'Actualizado',
|
||||
project_deleted_at: 'Eliminado',
|
||||
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_notes: 'Notas',
|
||||
@@ -669,7 +671,9 @@ export const messages = {
|
||||
project_updated_at: 'Updated',
|
||||
project_deleted_at: 'Deleted',
|
||||
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_notes: 'Notes',
|
||||
|
||||
@@ -22,7 +22,8 @@ import { DetailPopup } from '../../components/DetailPopup.jsx';
|
||||
import { SharedWithIcon } from '../../components/SharedWithIcon.jsx';
|
||||
|
||||
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 = []) {
|
||||
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 [filterPriorityId, setFilterPriorityId] = useState('');
|
||||
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; }
|
||||
// '' = todos, 'hide' = ocultar 100%, 'only' = solo 100%. Persistido en el navegador (sobrevive
|
||||
// al cierre de sesion). Respeta el checkbox anterior "Ocultar 100%" (clave vieja) si existia.
|
||||
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) {
|
||||
setHideCompleted(checked);
|
||||
try { localStorage.setItem(HIDE_COMPLETED_KEY, checked ? '1' : '0'); } catch { /* sin storage: solo en memoria */ }
|
||||
function changeProgressFilter(value) {
|
||||
setProgressFilter(value);
|
||||
try { localStorage.setItem(PROGRESS_FILTER_KEY, value); } catch { /* sin storage: solo en memoria */ }
|
||||
}
|
||||
const [filterOwnerUserId, setFilterOwnerUserId] = useState('');
|
||||
// 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;
|
||||
})
|
||||
: projects;
|
||||
const visibleProjects = hideCompleted && !showTrash
|
||||
? dueSoonProjects.filter((p) => Number(p.progress_pct) < 100)
|
||||
: dueSoonProjects;
|
||||
const visibleProjects = showTrash || !progressFilter
|
||||
? dueSoonProjects
|
||||
: dueSoonProjects.filter((p) => (Number(p.progress_pct) >= 100) === (progressFilter === 'only'));
|
||||
|
||||
return (
|
||||
<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')} />
|
||||
</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 && (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<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)} />
|
||||
{t('project_filter_due_soon')}
|
||||
</label>
|
||||
<label className="checkbox-row">
|
||||
<input type="checkbox" checked={hideCompleted} onChange={(e) => toggleHideCompleted(e.target.checked)} />
|
||||
{t('project_filter_hide_completed')}
|
||||
</label>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user