Implement urgency system with TaskWarrior-inspired calculation
- Add urgency calculation based on multiple factors: * Due date (linear scale: overdue=12.0, today=10.0, week=6.0, 2weeks=2.0) * Priority (H=6.0, M=3.9, D=1.8, L=0.0) * Age (0-2.0 over 365 days) * Active status (+4.0 boost) * Waiting status (-3.0 penalty) * Tags (+1.0 with count modifier) * Project assignment (+1.0) * Configurable urgent tag (default 'next', +15.0) - Replace priority column with urgency in all reports * Display as decimal with 1 decimal place * 4-tier color coding: ≥10 (bright red), ≥5 (red), ≥2 (yellow), <2 (cyan) * Minimal format color-coded by urgency - Add default urgency sorting to all reports * list, minimal, active, ready, overdue reports sort by urgency * newest/oldest keep date-based sorting - Implement 'next' report * Shows most urgent ready tasks * Configurable limit (default 5) * Only includes tasks ready to work on (no future wait/scheduled) - Add urgency display to info command * Shows urgency score alongside priority - All urgency coefficients configurable via config * Adjusted defaults for Opal's simpler model (no blocking/annotations) * Configurable urgent tag name (not hardcoded to 'next') Priority order maintained: High > Medium > Default > Low
This commit is contained in:
@@ -20,7 +20,11 @@ func FormatTaskListWithFormat(tasks []*Task, ws *WorkingSet, format string) stri
|
||||
return "No tasks found."
|
||||
}
|
||||
|
||||
// Minimal format: just ID and description
|
||||
// Get urgency coefficients
|
||||
cfg, _ := GetConfig()
|
||||
coeffs := BuildUrgencyCoefficients(cfg)
|
||||
|
||||
// Minimal format: just ID and description, color-coded by urgency
|
||||
if format == "minimal" {
|
||||
result := ""
|
||||
for i, task := range tasks {
|
||||
@@ -34,7 +38,9 @@ func FormatTaskListWithFormat(tasks []*Task, ws *WorkingSet, format string) stri
|
||||
}
|
||||
}
|
||||
}
|
||||
result += fmt.Sprintf("%3d %s\n", displayID, task.Description)
|
||||
urgency := task.CalculateUrgency(coeffs)
|
||||
urgencyColor := getUrgencyColor(urgency)
|
||||
result += urgencyColor.Sprintf("%3d %s\n", displayID, task.Description)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@@ -51,7 +57,7 @@ func FormatTaskListWithFormat(tasks []*Task, ws *WorkingSet, format string) stri
|
||||
t.SetColumnConfigs([]table.ColumnConfig{
|
||||
{Number: 1, WidthMin: 3, WidthMax: 3, Align: text.AlignRight}, // ID
|
||||
{Number: 2, WidthMin: 8, WidthMax: 8, Align: text.AlignLeft}, // Status
|
||||
{Number: 3, WidthMin: 3, WidthMax: 3, Align: text.AlignCenter}, // Pri
|
||||
{Number: 3, WidthMin: 4, WidthMax: 4, Align: text.AlignRight}, // Urg
|
||||
{Number: 4, WidthMin: 12, WidthMax: 12, Align: text.AlignLeft}, // Project
|
||||
{Number: 5, WidthMin: 40, WidthMax: 40, Align: text.AlignLeft, // Description
|
||||
WidthMaxEnforcer: text.Trim},
|
||||
@@ -60,7 +66,7 @@ func FormatTaskListWithFormat(tasks []*Task, ws *WorkingSet, format string) stri
|
||||
})
|
||||
|
||||
// Add header
|
||||
t.AppendHeader(table.Row{"ID", "Status", "Pri", "Project", "Description", "Due", "Tags"})
|
||||
t.AppendHeader(table.Row{"ID", "Status", "Urg", "Project", "Description", "Due", "Tags"})
|
||||
|
||||
// Add rows
|
||||
for i, task := range tasks {
|
||||
@@ -75,10 +81,11 @@ func FormatTaskListWithFormat(tasks []*Task, ws *WorkingSet, format string) stri
|
||||
}
|
||||
}
|
||||
|
||||
urgency := task.CalculateUrgency(coeffs)
|
||||
t.AppendRow(table.Row{
|
||||
displayID,
|
||||
formatStatus(task.Status),
|
||||
formatPriority(task.Priority),
|
||||
formatUrgency(urgency),
|
||||
formatProject(task.Project),
|
||||
task.Description,
|
||||
formatDue(task.Due),
|
||||
@@ -108,10 +115,16 @@ func FormatTaskDetail(task *Task) string {
|
||||
// Add title as header
|
||||
t.SetTitle(color.New(color.Bold).Sprint("Task Details"))
|
||||
|
||||
// Calculate urgency
|
||||
cfg, _ := GetConfig()
|
||||
coeffs := BuildUrgencyCoefficients(cfg)
|
||||
urgency := task.CalculateUrgency(coeffs)
|
||||
|
||||
// Core fields
|
||||
t.AppendRow(table.Row{"UUID", task.UUID})
|
||||
t.AppendRow(table.Row{"Status", formatStatus(task.Status)})
|
||||
t.AppendRow(table.Row{"Description", task.Description})
|
||||
t.AppendRow(table.Row{"Urgency", formatUrgency(urgency)})
|
||||
t.AppendRow(table.Row{"Priority", formatPriority(task.Priority)})
|
||||
t.AppendRow(table.Row{"Project", formatProject(task.Project)})
|
||||
|
||||
@@ -253,6 +266,38 @@ func formatPriority(priority Priority) string {
|
||||
}
|
||||
}
|
||||
|
||||
func formatUrgency(urgency float64) string {
|
||||
formatted := fmt.Sprintf("%.1f", urgency)
|
||||
|
||||
// 4-tier color coding
|
||||
if urgency >= 10.0 {
|
||||
// Critical urgency - bright red
|
||||
return color.New(color.FgHiRed, color.Bold).Sprint(formatted)
|
||||
} else if urgency >= 5.0 {
|
||||
// High urgency - red
|
||||
return color.RedString(formatted)
|
||||
} else if urgency >= 2.0 {
|
||||
// Medium urgency - yellow
|
||||
return color.YellowString(formatted)
|
||||
} else {
|
||||
// Low urgency - cyan
|
||||
return color.CyanString(formatted)
|
||||
}
|
||||
}
|
||||
|
||||
func getUrgencyColor(urgency float64) *color.Color {
|
||||
// Returns color for minimal format
|
||||
if urgency >= 10.0 {
|
||||
return color.New(color.FgHiRed, color.Bold)
|
||||
} else if urgency >= 5.0 {
|
||||
return color.New(color.FgRed)
|
||||
} else if urgency >= 2.0 {
|
||||
return color.New(color.FgYellow)
|
||||
} else {
|
||||
return color.New(color.FgCyan)
|
||||
}
|
||||
}
|
||||
|
||||
func formatProject(project *string) string {
|
||||
if project == nil {
|
||||
return "-"
|
||||
|
||||
Reference in New Issue
Block a user