This commit is contained in:
Trey t
2026-02-18 10:54:18 -06:00
parent a5245955af
commit 215e7c895d
11 changed files with 638 additions and 79 deletions

View File

@@ -346,7 +346,8 @@ func (r *TaskRepository) Unarchive(id uint) error {
// buildKanbanColumns builds the kanban column array from categorized task slices.
// This is a helper function to reduce duplication between GetKanbanData and GetKanbanDataForMultipleResidences.
// TEMPORARILY DISABLED: cancelled parameter removed - cancel column hidden from kanban
// Note: cancelled/archived tasks are intentionally hidden from the kanban board.
// They still retain "cancelled_tasks" as task-level categorization for detail views/actions.
func buildKanbanColumns(
overdue, inProgress, dueSoon, upcoming, completed []models.Task,
) []models.KanbanColumn {
@@ -396,7 +397,8 @@ func buildKanbanColumns(
Tasks: completed,
Count: len(completed),
},
// TEMPORARILY DISABLED - Cancel column hidden from kanban
// Intentionally hidden from board:
// cancelled/archived tasks are not returned as a kanban column.
// {
// Name: string(categorization.ColumnCancelled),
// DisplayName: "Cancelled",
@@ -451,7 +453,8 @@ func (r *TaskRepository) GetKanbanData(residenceID uint, daysThreshold int, now
return nil, fmt.Errorf("get completed tasks: %w", err)
}
// TEMPORARILY DISABLED - Cancel column hidden from kanban
// Intentionally hidden from board:
// cancelled/archived tasks are not returned as a kanban column.
// cancelled, err := r.GetCancelledTasks(opts)
// if err != nil {
// return nil, fmt.Errorf("get cancelled tasks: %w", err)
@@ -509,7 +512,8 @@ func (r *TaskRepository) GetKanbanDataForMultipleResidences(residenceIDs []uint,
return nil, fmt.Errorf("get completed tasks: %w", err)
}
// TEMPORARILY DISABLED - Cancel column hidden from kanban
// Intentionally hidden from board:
// cancelled/archived tasks are not returned as a kanban column.
// cancelled, err := r.GetCancelledTasks(opts)
// if err != nil {
// return nil, fmt.Errorf("get cancelled tasks: %w", err)

View File

@@ -306,7 +306,7 @@ func TestTaskRepository_CountByResidence(t *testing.T) {
// === Kanban Board Categorization Tests ===
func TestKanbanBoard_CancelledTasksGoToCancelledColumn(t *testing.T) {
func TestKanbanBoard_CancelledTasksHiddenFromKanbanBoard(t *testing.T) {
db := testutil.SetupTestDB(t)
repo := NewTaskRepository(db)
testutil.SeedLookupData(t, db)
@@ -321,22 +321,16 @@ func TestKanbanBoard_CancelledTasksGoToCancelledColumn(t *testing.T) {
board, err := repo.GetKanbanData(residence.ID, 30, time.Now().UTC())
require.NoError(t, err)
// Find cancelled column
var cancelledColumn *models.KanbanColumn
for i := range board.Columns {
if board.Columns[i].Name == "cancelled_tasks" {
cancelledColumn = &board.Columns[i]
break
}
assert.Len(t, board.Columns, 5, "board should have 5 visible columns")
for _, col := range board.Columns {
assert.NotEqual(t, "cancelled_tasks", col.Name, "cancelled column must be hidden")
}
require.NotNil(t, cancelledColumn, "cancelled_tasks column should exist")
assert.Equal(t, 1, cancelledColumn.Count)
assert.Len(t, cancelledColumn.Tasks, 1)
assert.Equal(t, "Cancelled Task", cancelledColumn.Tasks[0].Title)
// Verify button types for cancelled column
assert.ElementsMatch(t, []string{"uncancel", "delete"}, cancelledColumn.ButtonTypes)
totalTasks := 0
for _, col := range board.Columns {
totalTasks += col.Count
}
assert.Equal(t, 0, totalTasks, "cancelled task should be hidden from board")
}
func TestKanbanBoard_CompletedTasksGoToCompletedColumn(t *testing.T) {
@@ -566,7 +560,7 @@ func TestKanbanBoard_TasksWithNoDueDateGoToUpcomingColumn(t *testing.T) {
assert.Equal(t, task.ID, upcomingColumn.Tasks[0].ID)
}
func TestKanbanBoard_ArchivedTasksGoToCancelledColumn(t *testing.T) {
func TestKanbanBoard_ArchivedTasksHiddenFromKanbanBoard(t *testing.T) {
db := testutil.SetupTestDB(t)
repo := NewTaskRepository(db)
testutil.SeedLookupData(t, db)
@@ -582,38 +576,36 @@ func TestKanbanBoard_ArchivedTasksGoToCancelledColumn(t *testing.T) {
board, err := repo.GetKanbanData(residence.ID, 30, time.Now().UTC())
require.NoError(t, err)
// Find the cancelled column and verify archived task is there
var cancelledColumn *models.KanbanColumn
// Find the upcoming column and verify archived task is hidden
var upcomingColumn *models.KanbanColumn
foundCancelledColumn := false
for i := range board.Columns {
if board.Columns[i].Name == "cancelled_tasks" {
cancelledColumn = &board.Columns[i]
foundCancelledColumn = true
}
if board.Columns[i].Name == "upcoming_tasks" {
upcomingColumn = &board.Columns[i]
}
}
require.NotNil(t, cancelledColumn, "cancelled_tasks column should exist")
require.NotNil(t, upcomingColumn, "upcoming_tasks column should exist")
assert.False(t, foundCancelledColumn, "cancelled column must be hidden")
// Archived task should be in the cancelled column
assert.Equal(t, 1, cancelledColumn.Count, "archived task should be in cancelled column")
assert.Equal(t, "Archived Task", cancelledColumn.Tasks[0].Title)
// Archived task should be hidden from board
// Regular task should be in upcoming (no due date)
assert.Equal(t, 1, upcomingColumn.Count, "regular task should be in upcoming column")
assert.Equal(t, "Regular Task", upcomingColumn.Tasks[0].Title)
// Total tasks should be 2 (both appear in the board)
// Total tasks should be 1 (archived task is hidden)
totalTasks := 0
for _, col := range board.Columns {
totalTasks += col.Count
}
assert.Equal(t, 2, totalTasks, "both tasks should appear in the board")
assert.Equal(t, 1, totalTasks, "archived task should be hidden from board")
}
func TestKanbanBoard_ArchivedOverdueTask_GoesToCancelledNotOverdue(t *testing.T) {
func TestKanbanBoard_ArchivedOverdueTask_HiddenFromKanbanBoard(t *testing.T) {
db := testutil.SetupTestDB(t)
repo := NewTaskRepository(db)
testutil.SeedLookupData(t, db)
@@ -638,26 +630,30 @@ func TestKanbanBoard_ArchivedOverdueTask_GoesToCancelledNotOverdue(t *testing.T)
require.NoError(t, err)
// Find columns
var cancelledColumn, overdueColumn *models.KanbanColumn
var overdueColumn *models.KanbanColumn
foundCancelledColumn := false
for i := range board.Columns {
if board.Columns[i].Name == "cancelled_tasks" {
cancelledColumn = &board.Columns[i]
foundCancelledColumn = true
}
if board.Columns[i].Name == "overdue_tasks" {
overdueColumn = &board.Columns[i]
}
}
require.NotNil(t, cancelledColumn)
require.NotNil(t, overdueColumn)
assert.False(t, foundCancelledColumn, "cancelled column must be hidden")
// Archived task should be in cancelled, NOT overdue
assert.Equal(t, 1, cancelledColumn.Count, "archived task should be in cancelled column")
// Archived task should be hidden and NOT overdue
assert.Equal(t, 0, overdueColumn.Count, "archived task should NOT be in overdue column")
assert.Equal(t, "Archived Overdue Task", cancelledColumn.Tasks[0].Title)
totalTasks := 0
for _, col := range board.Columns {
totalTasks += col.Count
}
assert.Equal(t, 0, totalTasks, "archived task should be hidden from board")
}
func TestKanbanBoard_CategoryPriority_CancelledTakesPrecedence(t *testing.T) {
func TestKanbanBoard_CategoryPriority_CancelledTasksAreHidden(t *testing.T) {
db := testutil.SetupTestDB(t)
repo := NewTaskRepository(db)
testutil.SeedLookupData(t, db)
@@ -681,21 +677,26 @@ func TestKanbanBoard_CategoryPriority_CancelledTakesPrecedence(t *testing.T) {
board, err := repo.GetKanbanData(residence.ID, 30, time.Now().UTC())
require.NoError(t, err)
// Find cancelled column
var cancelledColumn *models.KanbanColumn
var overdueColumn *models.KanbanColumn
foundCancelledColumn := false
for i := range board.Columns {
if board.Columns[i].Name == "cancelled_tasks" {
cancelledColumn = &board.Columns[i]
foundCancelledColumn = true
}
if board.Columns[i].Name == "overdue_tasks" {
overdueColumn = &board.Columns[i]
}
}
// Task should be in cancelled, not overdue
assert.Equal(t, 1, cancelledColumn.Count, "Task should be in cancelled column")
// Cancelled task should be hidden and not appear as overdue
assert.False(t, foundCancelledColumn, "cancelled column must be hidden")
require.NotNil(t, overdueColumn, "overdue column should exist")
assert.Equal(t, 0, overdueColumn.Count, "Task should NOT be in overdue column")
totalTasks := 0
for _, col := range board.Columns {
totalTasks += col.Count
}
assert.Equal(t, 0, totalTasks, "cancelled task should be hidden from board")
}
func TestKanbanBoard_CategoryPriority_CompletedTakesPrecedenceOverInProgress(t *testing.T) {
@@ -808,7 +809,7 @@ func TestKanbanBoard_ColumnMetadata(t *testing.T) {
board, err := repo.GetKanbanData(residence.ID, 30, time.Now().UTC())
require.NoError(t, err)
// Verify all 6 columns exist with correct metadata
// Verify all 5 visible columns exist with correct metadata
expectedColumns := []struct {
name string
displayName string
@@ -822,10 +823,9 @@ func TestKanbanBoard_ColumnMetadata(t *testing.T) {
{"due_soon_tasks", "Due Soon", "#FF9500", []string{"edit", "complete", "cancel", "mark_in_progress"}, "clock", "Schedule"},
{"upcoming_tasks", "Upcoming", "#007AFF", []string{"edit", "complete", "cancel", "mark_in_progress"}, "calendar", "Event"},
{"completed_tasks", "Completed", "#34C759", []string{}, "checkmark.circle", "CheckCircle"}, // Completed tasks are read-only (no buttons)
{"cancelled_tasks", "Cancelled", "#8E8E93", []string{"uncancel", "delete"}, "xmark.circle", "Cancel"},
}
assert.Len(t, board.Columns, 6, "Board should have 6 columns")
assert.Len(t, board.Columns, 5, "Board should have 5 visible columns")
for i, expected := range expectedColumns {
col := board.Columns[i]
@@ -861,26 +861,28 @@ func TestKanbanBoard_MultipleResidences(t *testing.T) {
board, err := repo.GetKanbanDataForMultipleResidences([]uint{residence1.ID, residence2.ID}, 30, time.Now().UTC())
require.NoError(t, err)
// Count total tasks
// Count total tasks (cancelled task is intentionally hidden from board)
totalTasks := 0
for _, col := range board.Columns {
totalTasks += col.Count
}
assert.Equal(t, 3, totalTasks, "Should have 3 tasks total across both residences")
assert.Equal(t, 2, totalTasks, "Should have 2 visible tasks total across both residences")
// Find upcoming and cancelled columns
var upcomingColumn, cancelledColumn *models.KanbanColumn
// Find upcoming column and ensure cancelled column is hidden
var upcomingColumn *models.KanbanColumn
foundCancelledColumn := false
for i := range board.Columns {
if board.Columns[i].Name == "upcoming_tasks" {
upcomingColumn = &board.Columns[i]
}
if board.Columns[i].Name == "cancelled_tasks" {
cancelledColumn = &board.Columns[i]
foundCancelledColumn = true
}
}
assert.False(t, foundCancelledColumn, "cancelled column must be hidden")
require.NotNil(t, upcomingColumn, "upcoming column should exist")
assert.Equal(t, 2, upcomingColumn.Count, "Should have 2 upcoming tasks")
assert.Equal(t, 1, cancelledColumn.Count, "Should have 1 cancelled task")
}
// === Single-Purpose Function Tests ===
@@ -1562,7 +1564,8 @@ func TestKanbanBoardMatchesSinglePurposeFunctions(t *testing.T) {
require.NoError(t, err)
// Compare counts
var boardOverdue, boardDueSoon, boardInProgress, boardUpcoming, boardCompleted, boardCancelled int
var boardOverdue, boardDueSoon, boardInProgress, boardUpcoming, boardCompleted int
foundCancelledColumn := false
for _, col := range board.Columns {
switch col.Name {
case "overdue_tasks":
@@ -1576,7 +1579,7 @@ func TestKanbanBoardMatchesSinglePurposeFunctions(t *testing.T) {
case "completed_tasks":
boardCompleted = col.Count
case "cancelled_tasks":
boardCancelled = col.Count
foundCancelledColumn = true
}
}
@@ -1585,7 +1588,8 @@ func TestKanbanBoardMatchesSinglePurposeFunctions(t *testing.T) {
assert.Equal(t, len(inProgress), boardInProgress, "In Progress count mismatch")
assert.Equal(t, len(upcoming), boardUpcoming, "Upcoming count mismatch")
assert.Equal(t, len(completed), boardCompleted, "Completed count mismatch")
assert.Equal(t, len(cancelled), boardCancelled, "Cancelled count mismatch")
assert.False(t, foundCancelledColumn, "cancelled column must be hidden")
assert.NotEmpty(t, cancelled, "single-purpose cancelled query should still return cancelled tasks")
}
// === Additional Timezone Tests ===
@@ -2093,4 +2097,3 @@ func TestConsistency_OverduePredicateVsScopeVsRepo(t *testing.T) {
}
assert.Equal(t, expectedCount, len(repoTasks), "Overdue task count mismatch")
}