summaryrefslogtreecommitdiff
path: root/Omni/Jr
diff options
context:
space:
mode:
authorBen Sima <ben@bensima.com>2025-11-29 23:18:57 -0500
committerBen Sima <ben@bensima.com>2025-11-29 23:18:57 -0500
commitb5f3b9027aa0e96cd792f036a61d6b4418b39487 (patch)
tree2a29248e3a421ce989d75d6f8813ce2dd9d616f5 /Omni/Jr
parent82a2d55775eee2e34a26972774aaa6c5c0946743 (diff)
Sort /blocked page by blocking impact (transitive dependents)
All tests pass. The implementation is complete: **Summary of changes:** 1. **Omni/Task/Core.hs** - Added helper functions: - `getBlockingImpact`: Counts how many tasks are transitively blocked - `getTransitiveDependents`: Gets all tasks that depend on a task (di - `dependsOnTask`: Helper to check if a task depends on a given ID wi 2. **Omni/Jr/Web.hs** - Updated blocked page: - Changed `BlockedPage` type to include blocking impact: `[(TaskCore. - Updated `blockedHandler` to compute blocking impact and sort by it - Added `renderBlockedTaskCard` to display tasks with their blocking - Updated the info message to explain the sorting 3. **Omni/Jr/Web/Style.hs** - Added CSS: - `.blocking-impact` badge style (light mode) - `.blocking-impact` dark mode style Task-Id: t-189
Diffstat (limited to 'Omni/Jr')
-rw-r--r--Omni/Jr/Web.hs33
-rw-r--r--Omni/Jr/Web/Style.hs10
2 files changed, 35 insertions, 8 deletions
diff --git a/Omni/Jr/Web.hs b/Omni/Jr/Web.hs
index e00ebcd..2200bc0 100644
--- a/Omni/Jr/Web.hs
+++ b/Omni/Jr/Web.hs
@@ -254,7 +254,7 @@ data HomePage = HomePage TaskCore.TaskStats [TaskCore.Task] [TaskCore.Task] Bool
data ReadyQueuePage = ReadyQueuePage [TaskCore.Task] SortOrder UTCTime
-data BlockedPage = BlockedPage [TaskCore.Task] SortOrder UTCTime
+data BlockedPage = BlockedPage [(TaskCore.Task, Int)] SortOrder UTCTime
data InterventionPage = InterventionPage [TaskCore.Task] SortOrder UTCTime
@@ -889,6 +889,21 @@ renderTaskCard t =
Lucid.span_ [Lucid.class_ "priority"] (Lucid.toHtml (tshow (TaskCore.taskPriority t)))
Lucid.p_ [Lucid.class_ "task-title"] (Lucid.toHtml (TaskCore.taskTitle t))
+renderBlockedTaskCard :: (Monad m) => (TaskCore.Task, Int) -> Lucid.HtmlT m ()
+renderBlockedTaskCard (t, impact) =
+ Lucid.a_
+ [ Lucid.class_ "task-card task-card-link",
+ Lucid.href_ ("/tasks/" <> TaskCore.taskId t)
+ ]
+ <| do
+ Lucid.div_ [Lucid.class_ "task-header"] <| do
+ Lucid.span_ [Lucid.class_ "task-id"] (Lucid.toHtml (TaskCore.taskId t))
+ statusBadge (TaskCore.taskStatus t)
+ Lucid.span_ [Lucid.class_ "priority"] (Lucid.toHtml (tshow (TaskCore.taskPriority t)))
+ when (impact > 0)
+ <| Lucid.span_ [Lucid.class_ "blocking-impact"] (Lucid.toHtml ("Blocks " <> tshow impact))
+ Lucid.p_ [Lucid.class_ "task-title"] (Lucid.toHtml (TaskCore.taskTitle t))
+
renderListGroupItem :: (Monad m) => TaskCore.Task -> Lucid.HtmlT m ()
renderListGroupItem t =
Lucid.a_
@@ -1021,19 +1036,19 @@ instance Lucid.ToHtml ReadyQueuePage where
instance Lucid.ToHtml BlockedPage where
toHtmlRaw = Lucid.toHtml
- toHtml (BlockedPage tasks currentSort _now) =
+ toHtml (BlockedPage tasksWithImpact currentSort _now) =
let crumbs = [Breadcrumb "Jr" (Just "/"), Breadcrumb "Blocked" Nothing]
in Lucid.doctypehtml_ <| do
pageHead "Blocked Tasks - Jr"
pageBodyWithCrumbs crumbs <| do
Lucid.div_ [Lucid.class_ "container"] <| do
Lucid.div_ [Lucid.class_ "page-header-row"] <| do
- Lucid.h1_ <| Lucid.toHtml ("Blocked Tasks (" <> tshow (length tasks) <> " tasks)")
+ Lucid.h1_ <| Lucid.toHtml ("Blocked Tasks (" <> tshow (length tasksWithImpact) <> " tasks)")
sortDropdown "/blocked" currentSort
- Lucid.p_ [Lucid.class_ "info-msg"] "Tasks with unmet blocking dependencies."
- if null tasks
+ Lucid.p_ [Lucid.class_ "info-msg"] "Tasks with unmet blocking dependencies, sorted by blocking impact."
+ if null tasksWithImpact
then Lucid.p_ [Lucid.class_ "empty-msg"] "No blocked tasks."
- else Lucid.div_ [Lucid.class_ "task-list"] <| traverse_ renderTaskCard tasks
+ else Lucid.div_ [Lucid.class_ "task-list"] <| traverse_ renderBlockedTaskCard tasksWithImpact
instance Lucid.ToHtml InterventionPage where
toHtmlRaw = Lucid.toHtml
@@ -2421,9 +2436,11 @@ server =
blockedHandler maybeSortText = do
now <- liftIO getCurrentTime
blockedTasks <- liftIO TaskCore.getBlockedTasks
+ allTasks <- liftIO TaskCore.loadTasks
let sortOrder = parseSortOrder maybeSortText
- sortedTasks = sortTasks sortOrder blockedTasks
- pure (BlockedPage sortedTasks sortOrder now)
+ tasksWithImpact = [(t, TaskCore.getBlockingImpact allTasks t) | t <- blockedTasks]
+ sorted = List.sortBy (comparing (Down <. snd)) tasksWithImpact
+ pure (BlockedPage sorted sortOrder now)
interventionHandler :: Maybe Text -> Servant.Handler InterventionPage
interventionHandler maybeSortText = do
diff --git a/Omni/Jr/Web/Style.hs b/Omni/Jr/Web/Style.hs
index 11475d9..5090e2e 100644
--- a/Omni/Jr/Web/Style.hs
+++ b/Omni/Jr/Web/Style.hs
@@ -367,6 +367,13 @@ cardStyles = do
".priority" ? do
fontSize (px 11)
color "#6b7280"
+ ".blocking-impact" ? do
+ fontSize (px 10)
+ color "#6b7280"
+ backgroundColor "#e5e7eb"
+ padding (px 1) (px 6) (px 1) (px 6)
+ borderRadius (px 8) (px 8) (px 8) (px 8)
+ marginLeft auto
".task-title" ? do
fontSize (px 14)
margin (px 0) (px 0) (px 0) (px 0)
@@ -1556,6 +1563,9 @@ darkModeStyles =
".badge-p4" ? do
backgroundColor "#1f2937"
color "#9ca3af"
+ ".blocking-impact" ? do
+ backgroundColor "#374151"
+ color "#9ca3af"
".priority-dropdown-menu" ? do
backgroundColor "#1f2937"
Stylesheet.key "box-shadow" ("0 2px 8px rgba(0,0,0,0.3)" :: Text)