summaryrefslogtreecommitdiff
path: root/Omni
diff options
context:
space:
mode:
authorBen Sima <ben@bensima.com>2025-11-28 02:17:21 -0500
committerBen Sima <ben@bensima.com>2025-11-28 02:17:21 -0500
commit13edfda9ac34844f9922daf052db4b1050d9e853 (patch)
treefac2e2696c411c31f264447eeea859c74ccd4a8f /Omni
parent02cc1cadb77ece392d95e64b3778d0f33e93f51a (diff)
Add pagination to Recent Activity with HTMX load more button
The implementation is complete. Here's a summary: **Changes made:** 1. **API**: Added `QueryParam "offset" Int` to the `/partials/recent-act 2. **Data types**: - Updated `HomePage` to include a `Bool` for whether there are more t - Updated `RecentActivityPartial` to include `nextOffset :: Int` and 3. **Homepage rendering**: Shows a "Load More" button when there are mor 4. **Partial rendering**: The `RecentActivityPartial` now shows a "Load 5. **Handler**: `recentActivityHandler` now supports pagination with off 6. **Styling**: Added CSS for `.load-more-btn` and `.btn-secondary` clas The HTMX integration uses: - `hx-get` to fetch the next page with offset - `hx-target="closest .recent-activity"` to target the parent container - `hx-swap="beforeend"` to append new items (including another Load More Task-Id: t-151.4
Diffstat (limited to 'Omni')
-rw-r--r--Omni/Jr/Web.hs58
-rw-r--r--Omni/Jr/Web/Style.hs6
2 files changed, 47 insertions, 17 deletions
diff --git a/Omni/Jr/Web.hs b/Omni/Jr/Web.hs
index e58992c..465c021 100644
--- a/Omni/Jr/Web.hs
+++ b/Omni/Jr/Web.hs
@@ -76,7 +76,7 @@ type API =
:<|> "tasks" :> Capture "id" Text :> "accept" :> PostRedirect
:<|> "tasks" :> Capture "id" Text :> "reject" :> ReqBody '[FormUrlEncoded] RejectForm :> PostRedirect
:<|> "tasks" :> Capture "id" Text :> "reset-retries" :> PostRedirect
- :<|> "partials" :> "recent-activity" :> Get '[Lucid.HTML] RecentActivityPartial
+ :<|> "partials" :> "recent-activity" :> QueryParam "offset" Int :> Get '[Lucid.HTML] RecentActivityPartial
:<|> "partials" :> "ready-count" :> Get '[Lucid.HTML] ReadyCountPartial
:<|> "partials"
:> "task-list"
@@ -95,7 +95,7 @@ instance Accept CSS where
instance MimeRender CSS LazyText.Text where
mimeRender _ = LazyText.encodeUtf8
-data HomePage = HomePage TaskCore.TaskStats [TaskCore.Task] [TaskCore.Task]
+data HomePage = HomePage TaskCore.TaskStats [TaskCore.Task] [TaskCore.Task] Bool
newtype ReadyQueuePage = ReadyQueuePage [TaskCore.Task]
@@ -161,7 +161,7 @@ instance FromForm FactCreateForm where
data EpicsPage = EpicsPage [TaskCore.Task] [TaskCore.Task]
-newtype RecentActivityPartial = RecentActivityPartial [TaskCore.Task]
+data RecentActivityPartial = RecentActivityPartial [TaskCore.Task] Int Bool
newtype ReadyCountPartial = ReadyCountPartial Int
@@ -479,7 +479,7 @@ renderListGroupItem t =
instance Lucid.ToHtml HomePage where
toHtmlRaw = Lucid.toHtml
- toHtml (HomePage stats readyTasks recentTasks) =
+ toHtml (HomePage stats readyTasks recentTasks hasMoreRecent) =
Lucid.doctypehtml_ <| do
pageHead "Jr Dashboard"
Lucid.body_ <| do
@@ -518,11 +518,20 @@ instance Lucid.ToHtml HomePage where
Lucid.makeAttribute "hx-get" "/partials/recent-activity",
Lucid.makeAttribute "hx-trigger" "every 10s"
]
- <| if null recentTasks
- then Lucid.p_ [Lucid.class_ "empty-msg"] "No recent tasks."
- else
- Lucid.div_ [Lucid.class_ "list-group"]
- <| traverse_ renderListGroupItem recentTasks
+ <| do
+ if null recentTasks
+ then Lucid.p_ [Lucid.class_ "empty-msg"] "No recent tasks."
+ else
+ Lucid.div_ [Lucid.class_ "list-group"]
+ <| traverse_ renderListGroupItem recentTasks
+ when hasMoreRecent
+ <| Lucid.button_
+ [ Lucid.class_ "btn btn-secondary load-more-btn",
+ Lucid.makeAttribute "hx-get" "/partials/recent-activity?offset=5",
+ Lucid.makeAttribute "hx-target" "closest .recent-activity",
+ Lucid.makeAttribute "hx-swap" "beforeend"
+ ]
+ "Load More"
where
statCard :: (Monad m) => Text -> Int -> Text -> Text -> Lucid.HtmlT m ()
statCard label count badgeClass href =
@@ -1461,12 +1470,20 @@ instance Lucid.ToHtml StatsPage where
instance Lucid.ToHtml RecentActivityPartial where
toHtmlRaw = Lucid.toHtml
- toHtml (RecentActivityPartial recentTasks) =
+ toHtml (RecentActivityPartial recentTasks nextOffset hasMore) =
if null recentTasks
then Lucid.p_ [Lucid.class_ "empty-msg"] "No recent tasks."
- else
+ else do
Lucid.div_ [Lucid.class_ "list-group"]
<| traverse_ renderListGroupItem recentTasks
+ when hasMore
+ <| Lucid.button_
+ [ Lucid.class_ "btn btn-secondary load-more-btn",
+ Lucid.makeAttribute "hx-get" ("/partials/recent-activity?offset=" <> tshow nextOffset),
+ Lucid.makeAttribute "hx-target" "closest .recent-activity",
+ Lucid.makeAttribute "hx-swap" "beforeend"
+ ]
+ "Load More"
instance Lucid.ToHtml ReadyCountPartial where
toHtmlRaw = Lucid.toHtml
@@ -1706,8 +1723,10 @@ server =
stats <- liftIO <| TaskCore.getTaskStats Nothing
readyTasks <- liftIO TaskCore.getReadyTasks
allTasks <- liftIO TaskCore.loadTasks
- let recentTasks = take 5 <| List.sortBy (flip compare `on` TaskCore.taskUpdatedAt) allTasks
- pure (HomePage stats readyTasks recentTasks)
+ let sortedTasks = List.sortBy (flip compare `on` TaskCore.taskUpdatedAt) allTasks
+ recentTasks = take 5 sortedTasks
+ hasMoreRecent = length allTasks > 5
+ pure (HomePage stats readyTasks recentTasks hasMoreRecent)
readyQueueHandler :: Servant.Handler ReadyQueuePage
readyQueueHandler = do
@@ -1898,11 +1917,16 @@ server =
TaskCore.updateTaskStatus tid TaskCore.Open []
pure <| addHeader ("/tasks/" <> tid) NoContent
- recentActivityHandler :: Servant.Handler RecentActivityPartial
- recentActivityHandler = do
+ recentActivityHandler :: Maybe Int -> Servant.Handler RecentActivityPartial
+ recentActivityHandler maybeOffset = do
allTasks <- liftIO TaskCore.loadTasks
- let recentTasks = take 5 <| List.sortBy (flip compare `on` TaskCore.taskUpdatedAt) allTasks
- pure (RecentActivityPartial recentTasks)
+ let offset = fromMaybe 0 maybeOffset
+ pageSize = 5
+ sortedTasks = List.sortBy (flip compare `on` TaskCore.taskUpdatedAt) allTasks
+ pageTasks = take pageSize <| drop offset sortedTasks
+ hasMore = length sortedTasks > offset + pageSize
+ nextOffset = offset + pageSize
+ pure (RecentActivityPartial pageTasks nextOffset hasMore)
readyCountHandler :: Servant.Handler ReadyCountPartial
readyCountHandler = do
diff --git a/Omni/Jr/Web/Style.hs b/Omni/Jr/Web/Style.hs
index 7d6e7d6..866ed52 100644
--- a/Omni/Jr/Web/Style.hs
+++ b/Omni/Jr/Web/Style.hs
@@ -634,6 +634,12 @@ buttonStyles = do
color white
".review-link-btn" # hover ? backgroundColor "#7c3aed"
".review-link-section" ? margin (px 8) (px 0) (px 8) (px 0)
+ ".btn-secondary" <> ".load-more-btn" ? do
+ backgroundColor "#6b7280"
+ color white
+ width (pct 100)
+ marginTop (px 8)
+ ".btn-secondary" # hover <> ".load-more-btn" # hover ? backgroundColor "#4b5563"
formStyles :: Css
formStyles = do