Replace status_id with in_progress boolean field
- Remove task_statuses lookup table and StatusID foreign key - Add InProgress boolean field to Task model - Add database migration (005_replace_status_with_in_progress) - Update all handlers, services, and repositories - Update admin frontend to display in_progress as checkbox/boolean - Remove Task Statuses tab from admin lookups page - Update tests to use InProgress instead of StatusID - Task categorization now uses InProgress for kanban column assignment 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -73,22 +73,22 @@ func ScopeNotCompleted(db *gorm.DB) *gorm.DB {
|
||||
)
|
||||
}
|
||||
|
||||
// ScopeInProgress filters to tasks with status "In Progress".
|
||||
// ScopeInProgress filters to tasks marked as in progress.
|
||||
//
|
||||
// Predicate equivalent: IsInProgress(task)
|
||||
//
|
||||
// SQL: Joins task_taskstatus and filters by name = 'In Progress'
|
||||
// SQL: in_progress = true
|
||||
func ScopeInProgress(db *gorm.DB) *gorm.DB {
|
||||
return db.Joins("LEFT JOIN task_taskstatus ON task_taskstatus.id = task_task.status_id").
|
||||
Where("task_taskstatus.name = ?", "In Progress")
|
||||
return db.Where("in_progress = ?", true)
|
||||
}
|
||||
|
||||
// ScopeNotInProgress excludes tasks with status "In Progress".
|
||||
// ScopeNotInProgress excludes tasks marked as in progress.
|
||||
//
|
||||
// Predicate equivalent: !IsInProgress(task)
|
||||
//
|
||||
// SQL: in_progress = false
|
||||
func ScopeNotInProgress(db *gorm.DB) *gorm.DB {
|
||||
return db.Joins("LEFT JOIN task_taskstatus ON task_taskstatus.id = task_task.status_id").
|
||||
Where("task_taskstatus.name != ? OR task_taskstatus.name IS NULL", "In Progress")
|
||||
return db.Where("in_progress = ?", false)
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
|
||||
@@ -54,7 +54,6 @@ func TestMain(m *testing.M) {
|
||||
err = testDB.AutoMigrate(
|
||||
&models.Task{},
|
||||
&models.TaskCompletion{},
|
||||
&models.TaskStatus{},
|
||||
&models.Residence{},
|
||||
)
|
||||
if err != nil {
|
||||
@@ -77,7 +76,6 @@ func cleanupTestData() {
|
||||
}
|
||||
testDB.Exec("DELETE FROM task_taskcompletion WHERE task_id IN (SELECT id FROM task_task WHERE title LIKE 'test_%')")
|
||||
testDB.Exec("DELETE FROM task_task WHERE title LIKE 'test_%'")
|
||||
testDB.Exec("DELETE FROM task_taskstatus WHERE name LIKE 'test_%'")
|
||||
testDB.Exec("DELETE FROM residence_residence WHERE name LIKE 'test_%'")
|
||||
}
|
||||
|
||||
@@ -102,16 +100,6 @@ func createTestResidence(t *testing.T) uint {
|
||||
return residence.ID
|
||||
}
|
||||
|
||||
// createTestStatus creates a test status and returns it
|
||||
func createTestStatus(t *testing.T, name string) *models.TaskStatus {
|
||||
status := &models.TaskStatus{
|
||||
Name: "test_" + name,
|
||||
}
|
||||
if err := testDB.Create(status).Error; err != nil {
|
||||
t.Fatalf("Failed to create test status: %v", err)
|
||||
}
|
||||
return status
|
||||
}
|
||||
|
||||
// createTestTask creates a task with the given properties
|
||||
func createTestTask(t *testing.T, residenceID uint, task *models.Task) *models.Task {
|
||||
@@ -587,41 +575,18 @@ func TestScopeInProgressMatchesPredicate(t *testing.T) {
|
||||
}
|
||||
|
||||
residenceID := createTestResidence(t)
|
||||
|
||||
// For InProgress, we need to use the exact status name "In Progress" because
|
||||
// the scope joins on task_taskstatus.name = 'In Progress'
|
||||
// First, try to find existing "In Progress" status, or create one
|
||||
var inProgressStatus models.TaskStatus
|
||||
if err := testDB.Where("name = ?", "In Progress").First(&inProgressStatus).Error; err != nil {
|
||||
// Create it if it doesn't exist
|
||||
inProgressStatus = models.TaskStatus{Name: "In Progress"}
|
||||
testDB.Create(&inProgressStatus)
|
||||
}
|
||||
|
||||
var pendingStatus models.TaskStatus
|
||||
if err := testDB.Where("name = ?", "Pending").First(&pendingStatus).Error; err != nil {
|
||||
pendingStatus = models.TaskStatus{Name: "Pending"}
|
||||
testDB.Create(&pendingStatus)
|
||||
}
|
||||
|
||||
defer cleanupTestData()
|
||||
|
||||
// In progress task
|
||||
createTestTask(t, residenceID, &models.Task{
|
||||
Title: "in_progress",
|
||||
StatusID: &inProgressStatus.ID,
|
||||
Title: "in_progress",
|
||||
InProgress: true,
|
||||
})
|
||||
|
||||
// Not in progress: different status
|
||||
// Not in progress: InProgress is false
|
||||
createTestTask(t, residenceID, &models.Task{
|
||||
Title: "pending",
|
||||
StatusID: &pendingStatus.ID,
|
||||
})
|
||||
|
||||
// Not in progress: no status
|
||||
createTestTask(t, residenceID, &models.Task{
|
||||
Title: "no_status",
|
||||
StatusID: nil,
|
||||
Title: "not_in_progress",
|
||||
InProgress: false,
|
||||
})
|
||||
|
||||
// Query using scope
|
||||
@@ -633,9 +598,9 @@ func TestScopeInProgressMatchesPredicate(t *testing.T) {
|
||||
t.Fatalf("Scope query failed: %v", err)
|
||||
}
|
||||
|
||||
// Query all tasks with status preloaded and filter with predicate
|
||||
// Query all tasks and filter with predicate
|
||||
var allTasks []models.Task
|
||||
testDB.Preload("Status").Where("residence_id = ?", residenceID).Find(&allTasks)
|
||||
testDB.Where("residence_id = ?", residenceID).Find(&allTasks)
|
||||
|
||||
var predicateResults []models.Task
|
||||
for _, task := range allTasks {
|
||||
|
||||
Reference in New Issue
Block a user