From 166e4c84241450df8fb7a974b300769a8ff6bc49 Mon Sep 17 00:00:00 2001 From: "Claude (Chronicler #83 - The Compiler)" Date: Tue, 14 Apr 2026 12:13:41 -0500 Subject: [PATCH] Task module: 7 UX features (detail panel, sort, filters, presets, kanban, badges) 1. Click-to-open slide-out detail panel with full task info 2. Client-side sorting (number, priority, status, updated) with localStorage 3. Toggleable filter chips for status and priority 4. Saved filter presets (Launch Fires, Code Queue, Post-Launch, All Open) 5. Kanban board view with 4 columns (Open, In Progress, Blocked, Done) 6. Session summary badge showing tasks completed today 7. Code queue badge in sidebar nav (cyan count from tags) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../arbiter-3.0/src/routes/admin/index.js | 12 +- .../arbiter-3.0/src/routes/admin/tasks.js | 15 + .../src/views/admin/tasks/index.ejs | 498 ++++++++++++++++-- services/arbiter-3.0/src/views/layout.ejs | 7 +- 4 files changed, 471 insertions(+), 61 deletions(-) diff --git a/services/arbiter-3.0/src/routes/admin/index.js b/services/arbiter-3.0/src/routes/admin/index.js index f4e28d0..d0ce6a3 100644 --- a/services/arbiter-3.0/src/routes/admin/index.js +++ b/services/arbiter-3.0/src/routes/admin/index.js @@ -27,9 +27,17 @@ const nodeHealthRouter = require('./node-health'); router.use(requireTrinityAccess); -// Make CSRF token available to all admin views -router.use((req, res, next) => { +// Make CSRF token and code queue badge available to all admin views +router.use(async (req, res, next) => { res.locals.csrfToken = req.csrfToken(); + try { + const result = await db.query( + `SELECT COUNT(*) as count FROM tasks WHERE 'code' = ANY(tags) AND status IN ('open', 'in_progress')` + ); + res.locals.codeQueueCount = parseInt(result.rows[0].count) || 0; + } catch (e) { + res.locals.codeQueueCount = 0; + } next(); }); diff --git a/services/arbiter-3.0/src/routes/admin/tasks.js b/services/arbiter-3.0/src/routes/admin/tasks.js index 8c2e8cc..d10c3f0 100644 --- a/services/arbiter-3.0/src/routes/admin/tasks.js +++ b/services/arbiter-3.0/src/routes/admin/tasks.js @@ -54,11 +54,26 @@ router.get('/', async (req, res) => { FROM tasks `); + // Session summary: tasks completed today + const todayResult = await db.query( + `SELECT COUNT(*) as count FROM tasks WHERE completed_at::date = CURRENT_DATE` + ); + const completedToday = parseInt(todayResult.rows[0].count) || 0; + + // All tasks for kanban (unfiltered active tasks) + const kanbanResult = await db.query( + `SELECT * FROM tasks ORDER BY + CASE priority WHEN 'critical' THEN 1 WHEN 'high' THEN 2 WHEN 'medium' THEN 3 WHEN 'low' THEN 4 WHEN 'wish' THEN 5 END, + task_number` + ); + res.render('admin/tasks/index', { title: 'Tasks', currentPath: '/tasks', tasks: result.rows, + allTasks: kanbanResult.rows, stats: statsResult.rows[0], + completedToday, filters: { status, priority, owner, all: req.query.all }, priorities: PRIORITIES, statuses: STATUSES, diff --git a/services/arbiter-3.0/src/views/admin/tasks/index.ejs b/services/arbiter-3.0/src/views/admin/tasks/index.ejs index 120c69e..36c3eb7 100644 --- a/services/arbiter-3.0/src/views/admin/tasks/index.ejs +++ b/services/arbiter-3.0/src/views/admin/tasks/index.ejs @@ -1,5 +1,28 @@ + + + + + +<% if (completedToday > 0) { %> +
+ โœ… <%= completedToday %> task<%= completedToday !== 1 ? 's' : '' %> completed today +
+<% } %>
@@ -25,48 +48,66 @@
- -
-
-
- - + +
+
+ + +
+ +
+ + -
- - -
-
- - -
-
- - Reset - Show All -
- - +
+ +
+ +
- + +
+
+ Status: + + + + + + +
+
+ Priority: + + + + + + +
+
+ + +
+ Sort: + + + + +
+ + +
@@ -79,26 +120,38 @@ - + <% if (tasks.length === 0) { %> <% } %> <% tasks.forEach(task => { - const priColors = { critical:'bg-red-500/20 text-red-500', high:'bg-fire/20 text-fire', medium:'bg-yellow-500/20 text-yellow-500', low:'bg-blue-500/20 text-blue-400', wish:'bg-purple-500/20 text-purple-400' }; - const staColors = { open:'bg-gray-500/20 text-gray-400', in_progress:'bg-frost/20 text-frost', blocked:'bg-red-500/20 text-red-500', done:'bg-green-500/20 text-green-500', obsolete:'bg-gray-700/20 text-gray-600' }; - const priClass = priColors[task.priority] || 'bg-gray-500/20 text-gray-400'; - const staClass = staColors[task.status] || 'bg-gray-500/20 text-gray-400'; + var priColors = { critical:'bg-red-500/20 text-red-500', high:'bg-fire/20 text-fire', medium:'bg-yellow-500/20 text-yellow-500', low:'bg-blue-500/20 text-blue-400', wish:'bg-purple-500/20 text-purple-400' }; + var staColors = { open:'bg-gray-500/20 text-gray-400', in_progress:'bg-frost/20 text-frost', blocked:'bg-red-500/20 text-red-500', done:'bg-green-500/20 text-green-500', obsolete:'bg-gray-700/20 text-gray-600' }; + var priClass = priColors[task.priority] || 'bg-gray-500/20 text-gray-400'; + var staClass = staColors[task.status] || 'bg-gray-500/20 text-gray-400'; + var taskDesc = task.description || ''; + var taskTags = task.tags || []; + var taskSpecPath = task.spec_path || ''; + var taskCompletedBy = task.completed_by || ''; + var taskCreatedAt = task.created_at ? new Date(task.created_at).toLocaleDateString() : ''; + var taskUpdatedAt = task.updated_at ? new Date(task.updated_at).toLocaleDateString() : ''; + var taskCompletedAt = task.completed_at ? new Date(task.completed_at).toLocaleDateString() : ''; %> - + @@ -140,9 +193,102 @@
Actions
No tasks match your filters.
<%= task.task_number %> -
<%= task.title %>
- <% if (task.description) { %> -
<%= task.description.substring(0, 80) %><%= task.description.length > 80 ? '...' : '' %>
+
<%= task.title %>
+ <% if (taskDesc) { %> +
<%= taskDesc.substring(0, 80) %><%= taskDesc.length > 80 ? '...' : '' %>
<% } %> - <% if (task.tags && task.tags.length > 0) { %> + <% if (taskTags.length > 0) { %>
- <% task.tags.forEach(tag => { %> + <% taskTags.forEach(function(tag) { %> <%= tag %> <% }); %>
@@ -110,7 +163,7 @@
@@ -119,7 +172,7 @@
@@ -131,8 +184,8 @@ - <% } else if (task.completed_by) { %> - <%= task.completed_by %> + <% } else if (taskCompletedBy) { %> + <%= taskCompletedBy %> <% } %>
-
- <%= tasks.length %> task(s) shown ยท Source: PostgreSQL ยท Also available via /tasks in Discord + <%= tasks.length %> task(s) shown ยท Source: PostgreSQL ยท Also available via /tasks in Discord +
+
+ + + + + + +
+
+
+ + +
+

+
+ + +
+
+
+ Owner + +
+
+ Description +
+
+
+ Tags +
+
+
+
+ Created + +
+
+ Updated + +
+
+ + +
+
@@ -154,7 +300,7 @@
@@ -197,3 +343,241 @@
+ + diff --git a/services/arbiter-3.0/src/views/layout.ejs b/services/arbiter-3.0/src/views/layout.ejs index 7901486..8393b3e 100644 --- a/services/arbiter-3.0/src/views/layout.ejs +++ b/services/arbiter-3.0/src/views/layout.ejs @@ -102,8 +102,11 @@ ๐Ÿ“Š Dashboard - - ๐Ÿ“‹ Tasks + + ๐Ÿ“‹ Tasks + <% if (typeof codeQueueCount !== 'undefined' && codeQueueCount > 0) { %> + <%= codeQueueCount %> + <% } %> ๐Ÿ–ฅ๏ธ Servers