summaryrefslogtreecommitdiff
path: root/Omni/Task
diff options
context:
space:
mode:
Diffstat (limited to 'Omni/Task')
-rw-r--r--Omni/Task/Core.hs62
1 files changed, 35 insertions, 27 deletions
diff --git a/Omni/Task/Core.hs b/Omni/Task/Core.hs
index 622e8de..3f665da 100644
--- a/Omni/Task/Core.hs
+++ b/Omni/Task/Core.hs
@@ -89,6 +89,14 @@ instance ToJSON Task
instance FromJSON Task
+-- | Case-insensitive ID comparison
+matchesId :: Text -> Text -> Bool
+matchesId id1 id2 = T.toLower id1 == T.toLower id2
+
+-- | Find a task by ID (case-insensitive)
+findTask :: Text -> [Task] -> Maybe Task
+findTask tid = List.find (\t -> matchesId (taskId t) tid)
+
instance ToJSON TaskProgress
instance FromJSON TaskProgress
@@ -258,7 +266,7 @@ updateTaskStatus tid newStatus = do
now <- getCurrentTime
let updatedTasks = map updateIfMatch tasks
updateIfMatch t =
- if taskId t == tid
+ if matchesId (taskId t) tid
then t {taskStatus = newStatus, taskUpdatedAt = now}
else t
-- Rewrite the entire file (simple approach for MVP)
@@ -311,14 +319,14 @@ getReadyTasks = do
getDependencyTree :: Text -> IO [Task]
getDependencyTree tid = do
tasks <- loadTasks
- case filter (\t -> taskId t == tid) tasks of
- [] -> pure []
- (task : _) -> pure <| collectDeps tasks task
+ case findTask tid tasks of
+ Nothing -> pure []
+ Just task -> pure <| collectDeps tasks task
where
collectDeps :: [Task] -> Task -> [Task]
collectDeps allTasks task =
let depIds = map depId (taskDependencies task)
- deps = filter (\t -> taskId t `elem` depIds) allTasks
+ deps = filter (\t -> any (matchesId (taskId t)) depIds) allTasks
in task : concatMap (collectDeps allTasks) deps
-- Get task progress
@@ -351,15 +359,15 @@ showTaskProgress tid = do
showDependencyTree :: Text -> IO ()
showDependencyTree tid = do
tasks <- loadTasks
- case filter (\t -> taskId t == tid) tasks of
- [] -> putText "Task not found"
- (task : _) -> printTree tasks task 0
+ case findTask tid tasks of
+ Nothing -> putText "Task not found"
+ Just task -> printTree tasks task 0
where
printTree :: [Task] -> Task -> Int -> IO ()
printTree allTasks task indent = do
putText <| T.pack (replicate (indent * 2) ' ') <> taskId task <> ": " <> taskTitle task
let depIds = map depId (taskDependencies task)
- deps = filter (\t -> taskId t `elem` depIds) allTasks
+ deps = filter (\t -> any (matchesId (taskId t)) depIds) allTasks
traverse_ (\dep -> printTree allTasks dep (indent + 1)) deps
-- Get task tree (returns tasks hierarchically)
@@ -373,13 +381,13 @@ getTaskTree maybeId = do
in pure <| concatMap (collectChildren tasks) epics
Just tid -> do
-- Return specific task/epic with its children
- case filter (\t -> taskId t == tid) tasks of
- [] -> pure []
- (task : _) -> pure <| collectChildren tasks task
+ case findTask tid tasks of
+ Nothing -> pure []
+ Just task -> pure <| collectChildren tasks task
where
collectChildren :: [Task] -> Task -> [Task]
collectChildren allTasks task =
- let children = filter (\t -> taskParent t == Just (taskId task)) allTasks
+ let children = filter (maybe False (`matchesId` taskId task) <. taskParent) allTasks
in task : concatMap (collectChildren allTasks) children
-- Show task tree (epic with children, or all epics if no ID given)
@@ -395,9 +403,9 @@ showTaskTree maybeId = do
else traverse_ (printEpicTree tasks) epics
Just tid -> do
-- Show specific task/epic with its children
- case filter (\t -> taskId t == tid) tasks of
- [] -> putText "Task not found"
- (task : _) -> printEpicTree tasks task
+ case findTask tid tasks of
+ Nothing -> putText "Task not found"
+ Just task -> printEpicTree tasks task
where
printEpicTree :: [Task] -> Task -> IO ()
printEpicTree allTasks task = printTreeNode allTasks task 0
@@ -407,7 +415,7 @@ showTaskTree maybeId = do
printTreeNode' :: [Task] -> Task -> Int -> [Bool] -> IO ()
printTreeNode' allTasks task indent ancestry = do
- let children = filter (\t -> taskParent t == Just (taskId task)) allTasks
+ let children = filter (maybe False (`matchesId` taskId task) <. taskParent) allTasks
-- Build tree prefix using box-drawing characters
prefix =
if indent == 0
@@ -456,7 +464,7 @@ printTask t = do
let progressInfo =
if taskType t == Epic
then
- let children = filter (\child -> taskParent child == Just (taskId t)) tasks
+ let children = filter (maybe False (`matchesId` taskId t) <. taskParent) tasks
total = length children
completed = length <| filter (\child -> taskStatus child == Done) children
in " [" <> T.pack (show completed) <> "/" <> T.pack (show total) <> "]"
@@ -494,7 +502,7 @@ showTaskDetailed t = do
-- Show epic progress if this is an epic
when (taskType t == Epic) <| do
- let children = filter (\child -> taskParent child == Just (taskId t)) tasks
+ let children = filter (maybe False (`matchesId` taskId t) <. taskParent) tasks
total = length children
completed = length <| filter (\child -> taskStatus child == Done) children
percentage = if total == 0 then 0 else (completed * 100) `div` total
@@ -563,9 +571,9 @@ getTaskStats maybeEpicId = do
targetTasks <- case maybeEpicId of
Nothing -> pure allTasks
Just epicId ->
- case filter (\t -> taskId t == epicId) allTasks of
- [] -> panic "Epic not found"
- _ -> pure <| getAllDescendants allTasks epicId
+ case findTask epicId allTasks of
+ Nothing -> panic "Epic not found"
+ Just task -> pure <| getAllDescendants allTasks (taskId task)
globalReady <- getReadyTasks
let readyIds = map taskId globalReady
@@ -610,7 +618,7 @@ getTaskStats maybeEpicId = do
-- Helper to get all descendants of a task (recursive)
getAllDescendants :: [Task] -> Text -> [Task]
getAllDescendants allTasks parentId =
- let children = filter (\t -> taskParent t == Just parentId) allTasks
+ let children = filter (maybe False (`matchesId` parentId) <. taskParent) allTasks
in children ++ concatMap (getAllDescendants allTasks <. taskId) children
-- Show task statistics (human-readable)
@@ -669,7 +677,7 @@ importTasks filePath = do
-- Create a map of existing task IDs for quick lookup
let existingIds = map taskId existingTasks
-- Filter to only new tasks (not already in our database)
- newTasks = filter (\t -> taskId t `notElem` existingIds) importedTasks
+ newTasks = filter (\t -> not (any (`matchesId` taskId t) existingIds)) importedTasks
-- For tasks that exist, update them with imported data
updatedTasks = map (updateWithImported importedTasks) existingTasks
-- Combine: updated existing tasks + new tasks
@@ -689,9 +697,9 @@ importTasks filePath = do
-- Update an existing task if there's a newer version in imported tasks
updateWithImported :: [Task] -> Task -> Task
updateWithImported imported existing =
- case filter (\t -> taskId t == taskId existing) imported of
- [] -> existing -- No imported version, keep existing
- (importedTask : _) ->
+ case findTask (taskId existing) imported of
+ Nothing -> existing -- No imported version, keep existing
+ Just importedTask ->
-- Use imported version if it's newer (based on updatedAt)
if taskUpdatedAt importedTask > taskUpdatedAt existing
then importedTask