diff --git a/index.html b/index.html index d3dd4bc..a0f0be3 100644 --- a/index.html +++ b/index.html @@ -462,7 +462,22 @@ -
+
+ + + + + + + + + + + + + + +
@@ -585,7 +600,20 @@ -
+
+ + + + + + + + + + + + +
diff --git a/script.js b/script.js index 4255524..d0a1b94 100644 --- a/script.js +++ b/script.js @@ -3943,28 +3943,45 @@ function renderTasksList() { if (query) tasks = tasks.filter(t => (t.title||'').toLowerCase().includes(query) || (t.description||'').toLowerCase().includes(query) || (t.assigned_to||'').toLowerCase().includes(query)); if (statusF) tasks = tasks.filter(t => t.status === statusF); if (assignF) tasks = tasks.filter(t => t.assigned_to === assignF); - const grid = document.getElementById('tasks-grid'); - const noEl = document.getElementById('no-tasks'); - if (!grid) return; - if (!tasks.length) { grid.innerHTML = ''; if (noEl) noEl.style.display = ''; return; } - if (noEl) noEl.style.display = 'none'; + + // Lajittelu: deadline lähimmät ensin (null-deadlinet loppuun), sitten prioriteetti const today = new Date().toISOString().slice(0,10); - grid.innerHTML = tasks.map(t => { + const prioOrder = { kiireellinen: 0, tarkea: 1, normaali: 2 }; + const statusOrder = { avoin: 0, kaynnissa: 1, odottaa: 2, valmis: 3 }; + tasks.sort((a, b) => { + // Valmiit aina loppuun + if ((a.status === 'valmis') !== (b.status === 'valmis')) return a.status === 'valmis' ? 1 : -1; + // Deadline: lähimmät ensin, null loppuun + const da = a.deadline || '9999-99-99'; + const db = b.deadline || '9999-99-99'; + if (da !== db) return da.localeCompare(db); + // Prioriteetti + const pa = prioOrder[a.priority] ?? 2; + const pb = prioOrder[b.priority] ?? 2; + if (pa !== pb) return pa - pb; + return 0; + }); + + const tbody = document.getElementById('tasks-tbody'); + const table = document.getElementById('tasks-table'); + const noEl = document.getElementById('no-tasks'); + if (!tbody) return; + if (!tasks.length) { tbody.innerHTML = ''; table.style.display = 'none'; if (noEl) noEl.style.display = ''; return; } + if (noEl) noEl.style.display = 'none'; + table.style.display = 'table'; + tbody.innerHTML = tasks.map(t => { const overdue = t.deadline && t.status !== 'valmis' && t.deadline < today; const soon = t.deadline && t.status !== 'valmis' && !overdue && t.deadline <= new Date(Date.now()+3*86400000).toISOString().slice(0,10); - return `
-
- ${todoPriorityLabels[t.priority]||t.priority} - ${todoStatusLabels[t.status]||t.status} -
-
${esc(t.title)}
-
- ${t.assigned_to ? `👤 ${esc(t.assigned_to)}` : ''} - ${t.deadline ? `📅 ${t.deadline}` : ''} - ${t.total_hours > 0 ? `⏱ ${t.total_hours}h` : ''} - ${t.comment_count > 0 ? `💬 ${t.comment_count}` : ''} -
-
`; + const rowClass = overdue ? 'todo-row-overdue' : (soon ? 'todo-row-soon' : (t.status === 'valmis' ? 'todo-row-done' : '')); + return ` + ${todoStatusLabels[t.status]||t.status} + ${todoPriorityLabels[t.priority]||t.priority} + ${esc(t.title)} + ${t.assigned_to ? esc(t.assigned_to) : ''} + ${t.deadline ? `${t.deadline}` : ''} + ${t.total_hours > 0 ? t.total_hours + 'h' : ''} + ${t.comment_count > 0 ? t.comment_count : ''} + `; }).join(''); } @@ -4093,20 +4110,33 @@ function renderFeaturesList() { let features = todosData.filter(t => t.type === 'feature_request'); if (query) features = features.filter(t => (t.title||'').toLowerCase().includes(query) || (t.description||'').toLowerCase().includes(query)); if (statusF) features = features.filter(t => t.status === statusF); - const grid = document.getElementById('features-grid'); + + // Lajittelu: uusimmat ensin, toteutetut/hylätyt loppuun + features.sort((a, b) => { + const doneA = (a.status === 'toteutettu' || a.status === 'hylatty') ? 1 : 0; + const doneB = (b.status === 'toteutettu' || b.status === 'hylatty') ? 1 : 0; + if (doneA !== doneB) return doneA - doneB; + return (b.luotu || '').localeCompare(a.luotu || ''); + }); + + const tbody = document.getElementById('features-tbody'); + const table = document.getElementById('features-table'); const noEl = document.getElementById('no-features'); - if (!grid) return; - if (!features.length) { grid.innerHTML = ''; if (noEl) noEl.style.display = ''; return; } + if (!tbody) return; + if (!features.length) { tbody.innerHTML = ''; table.style.display = 'none'; if (noEl) noEl.style.display = ''; return; } if (noEl) noEl.style.display = 'none'; - grid.innerHTML = features.map(t => `
-
${todoStatusLabels[t.status]||t.status}
-
${esc(t.title)}
-
- 👤 ${esc(t.created_by)} - ${(t.luotu||'').slice(0,10)} - ${t.comment_count > 0 ? `💬 ${t.comment_count}` : ''} -
-
`).join(''); + table.style.display = 'table'; + tbody.innerHTML = features.map(t => { + const done = t.status === 'toteutettu' || t.status === 'hylatty'; + const rowClass = done ? 'todo-row-done' : ''; + return ` + ${todoStatusLabels[t.status]||t.status} + ${esc(t.title)} + ${esc(t.created_by)} + ${(t.luotu||'').slice(0,10)} + ${t.comment_count > 0 ? t.comment_count : ''} + `; + }).join(''); } function showFeatureListView() { diff --git a/style.css b/style.css index 8a7eb42..d3897d3 100644 --- a/style.css +++ b/style.css @@ -1129,6 +1129,12 @@ span.empty { .todo-card:hover { transform:translateY(-2px); box-shadow:0 4px 12px rgba(0,0,0,0.1); border-color:var(--primary-color); } .todo-card.overdue { border-color:#e74c3c; } .todo-card.deadline-soon { border-color:#f39c12; } +.todo-row-overdue { background:#fef2f2 !important; } +.todo-row-overdue:hover { background:#fde8e8 !important; } +.todo-row-soon { background:#fffbeb !important; } +.todo-row-soon:hover { background:#fef3c7 !important; } +.todo-row-done { opacity:0.55; } +.todo-row-done:hover { opacity:0.75; } .priority-badge { display:inline-block; padding:2px 8px; border-radius:10px; font-size:0.72rem; font-weight:600; } .priority-normaali { background:#e8ebf0; color:#555; } .priority-tarkea { background:#fff3cd; color:#856404; }