Skip to content

Commit 59b17a1

Browse files
committed
Add cron sorting using standard component
1 parent d311bc4 commit 59b17a1

File tree

4 files changed

+106
-25
lines changed

4 files changed

+106
-25
lines changed

lib/oban/web/pages/crons_page.ex

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ defmodule Oban.Web.CronsPage do
33

44
use Oban.Web, :live_component
55

6-
alias Oban.Web.{Cron, CronQuery, Page}
6+
alias Oban.Web.{Cron, CronQuery, Page, SortComponent}
7+
8+
@known_params ~w(sort_by sort_dir)
79

810
@impl Phoenix.LiveComponent
911
def render(assigns) do
@@ -19,6 +21,15 @@ defmodule Oban.Web.CronsPage do
1921
2022
<h2 class="text-lg dark:text-gray-200 leading-4 font-bold">Crons</h2>
2123
</div>
24+
25+
<div class="pl-3 ml-auto">
26+
<SortComponent.select
27+
id="crons-sort"
28+
by={~w(worker schedule last_run next_run)}
29+
page={:crons}
30+
params={@params}
31+
/>
32+
</div>
2233
</div>
2334
2435
<div id="crons-table" class="min-w-full">
@@ -107,7 +118,7 @@ defmodule Oban.Web.CronsPage do
107118
108119
<div class="w-20 pr-3 flex justify-end items-center space-x-1">
109120
<span
110-
id={"cron-state-icon-#{@cron.worker}"}
121+
id={"cron-state-icon-#{Cron.name(@cron)}"}
111122
class="py-1.5 px-2 text-xs"
112123
phx-hook="Tippy"
113124
data-title={state_title(@cron)}
@@ -158,17 +169,32 @@ defmodule Oban.Web.CronsPage do
158169

159170
@impl Page
160171
def handle_mount(socket) do
161-
assign_new(socket, :crontab, fn -> crontab(socket.assigns.conf) end)
172+
default = fn -> %{sort_by: "worker", sort_dir: "asc"} end
173+
174+
socket
175+
|> assign_new(:default_params, default)
176+
|> assign_new(:params, default)
177+
|> assign_new(:crontab, fn -> crontab(socket.assigns.conf) end)
162178
end
163179

164180
@impl Page
165181
def handle_refresh(socket) do
166-
assign(socket, crontab: crontab(socket.assigns.conf))
182+
crons = CronQuery.all_crons(socket.assigns.params, socket.assigns.conf)
183+
assign(socket, crontab: crons)
167184
end
168185

169186
@impl Page
170-
def handle_params(_params, _uri, socket) do
171-
socket = assign(socket, page_title: page_title("Crons"))
187+
def handle_params(params, _uri, socket) do
188+
params =
189+
params
190+
|> Map.take(@known_params)
191+
|> decode_params()
192+
193+
socket =
194+
socket
195+
|> assign(page_title: page_title("Crons"))
196+
|> assign(params: Map.merge(socket.assigns.default_params, params))
197+
|> handle_refresh()
172198

173199
{:noreply, socket}
174200
end

lib/oban/web/queries/cron_query.ex

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,35 @@ defmodule Oban.Web.CronQuery do
77
alias Oban.{Job, Met, Repo}
88
alias Oban.Web.Cron
99

10-
def all_crons(_params, conf) do
10+
def all_crons(params, conf) do
11+
{sort_by, sort_dir} = parse_sort(params)
12+
1113
# TODO: Cache these values and avoid running the query too frequently
1214
crontab = Met.crontab(conf.name)
13-
workers = Enum.map(crontab, &elem(&1, 1))
14-
history = crontab_history(workers, conf)
15-
16-
for {expr, worker, opts} <- crontab do
17-
fields = [
18-
expression: expr,
19-
worker: worker,
20-
opts: opts,
21-
next_at: next_at(expr),
22-
last_at: last_at(history, worker),
23-
last_state: get_in(history, [worker, :state])
24-
]
25-
26-
struct!(Cron, fields)
27-
end
15+
16+
history =
17+
crontab
18+
|> Enum.map(&elem(&1, 1))
19+
|> crontab_history(conf)
20+
21+
crontab
22+
|> Enum.map(&new(&1, history))
23+
|> Enum.sort_by(&order(&1, sort_by), sort_dir)
24+
end
25+
26+
# Construction
27+
28+
defp new({expr, worker, opts}, history) do
29+
fields = [
30+
expression: expr,
31+
worker: worker,
32+
opts: opts,
33+
next_at: next_at(expr),
34+
last_at: last_at(history, worker),
35+
last_state: get_in(history, [worker, :state])
36+
]
37+
38+
struct!(Cron, fields)
2839
end
2940

3041
# TODO: Correctly handle jobs with different args
@@ -76,4 +87,26 @@ defmodule Oban.Web.CronQuery do
7687
|> Expression.parse!()
7788
|> Expression.next_at()
7889
end
90+
91+
# Sorting
92+
93+
defp parse_sort(%{sort_by: "last_run", sort_dir: dir}) do
94+
{:last_run, {String.to_existing_atom(dir), DateTime}}
95+
end
96+
97+
defp parse_sort(%{sort_by: "next_run", sort_dir: dir}) do
98+
{:next_run, {String.to_existing_atom(dir), DateTime}}
99+
end
100+
101+
defp parse_sort(%{sort_by: sby, sort_dir: dir}) do
102+
{String.to_existing_atom(sby), String.to_existing_atom(dir)}
103+
end
104+
105+
defp parse_sort(_params), do: {:worker, :asc}
106+
107+
defp order(%{last_at: nil}, :last_run), do: ~U[2000-01-01 00:00:00Z]
108+
defp order(%{last_at: last_at}, :last_run), do: last_at
109+
defp order(%{next_at: next_at}, :next_run), do: next_at
110+
defp order(%{expression: expression}, :schedule), do: expression
111+
defp order(%{worker: worker}, :worker), do: worker
79112
end

lib/oban/web/queries/queue_query.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ defmodule Oban.Web.QueueQuery do
9393
# Querying
9494

9595
def all_queues(params, %{name: name}) do
96-
{sort_by, sort_dir} = atomize_sort(params)
96+
{sort_by, sort_dir} = parse_sort(params)
9797

9898
conditions = Map.take(params, filterable())
9999

@@ -116,11 +116,11 @@ defmodule Oban.Web.QueueQuery do
116116
struct!(Queue, %{name: name, checks: checks, counts: counts})
117117
end
118118

119-
defp atomize_sort(%{sort_by: sby, sort_dir: dir}) do
119+
defp parse_sort(%{sort_by: sby, sort_dir: dir}) do
120120
{String.to_existing_atom(sby), String.to_existing_atom(dir)}
121121
end
122122

123-
defp atomize_sort(_params), do: {:name, :asc}
123+
defp parse_sort(_params), do: {:name, :asc}
124124

125125
# Filtering
126126

test/oban/web/pages/crons/index_test.exs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,28 @@ defmodule Oban.Web.Pages.Crons.IndexTest do
4444
assert table =~ ~r/cron-Oban-Workers-CronB/
4545
end
4646

47+
test "sorting crons by different properties", %{live: live} do
48+
refresh(live)
49+
50+
assert has_element?(live, "#crons-sort")
51+
52+
for mode <- ~w(worker last_run next_run schedule) do
53+
change_sort(live, mode)
54+
55+
assert_patch(live, crons_path(sort_by: mode, sort_dir: "asc"))
56+
end
57+
end
58+
59+
defp change_sort(live, mode) do
60+
live
61+
|> element("a#sort-#{mode}")
62+
|> render_click()
63+
end
64+
65+
defp crons_path(params) do
66+
"/oban/crons?#{URI.encode_query(params)}"
67+
end
68+
4769
defp refresh(live) do
4870
send(live.pid, :refresh)
4971
end

0 commit comments

Comments
 (0)