Skip to content

Commit a355a94

Browse files
committed
Refactor notifications API to be a thinner wrapper around PubSub
1 parent af134f5 commit a355a94

File tree

8 files changed

+106
-81
lines changed

8 files changed

+106
-81
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Significant features:
1414
* Overridable views, styles, and API
1515
* Custom actions at the resource and record level, with support for dynamic inputs
1616
* Edit (nested) embedded schemas
17-
* Notifications
17+
* Notifications via [Phoenix.PubSub](https://github.com/phoenixframework/phoenix_pubsub)
1818
* i18n via [Gettext](https://github.com/elixir-gettext/gettext)
1919

2020
See for yourself, try out the [demo app](#development)
@@ -154,7 +154,7 @@ A dropdown will be added to the top nav bar that will allow you to switch betwee
154154
155155
### Notifications
156156
157-
`LiveAdmin.Notifier` provides an API for triggering events from LiveAdmin.Resource modules, or other application code.
157+
LiveAdmin broadcasts notifications about certain events and responds with UI events.
158158
159159
Currently supported:
160160

README.md.eex

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Significant features:
1414
* Overridable views, styles, and API
1515
* Custom actions at the resource and record level, with support for dynamic inputs
1616
* Edit (nested) embedded schemas
17-
* Notifications
17+
* Notifications via [Phoenix.PubSub](https://github.com/phoenixframework/phoenix_pubsub)
1818
* i18n via [Gettext](https://github.com/elixir-gettext/gettext)
1919

2020
See for yourself, try out the [demo app](#development)
@@ -154,7 +154,7 @@ A dropdown will be added to the top nav bar that will allow you to switch betwee
154154

155155
### Notifications
156156

157-
`LiveAdmin.Notifier` provides an API for triggering events from LiveAdmin.Resource modules, or other application code.
157+
LiveAdmin broadcasts notifications about certain events and responds with UI events.
158158

159159
Currently supported:
160160

dev/user_admin.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ defmodule DemoWeb.UserAdmin do
7272
|> Ecto.Changeset.change(encrypted_password: :crypto.strong_rand_bytes(16) |> Base.encode16())
7373
|> Demo.Repo.update()
7474

75-
LiveAdmin.Notifier.job(session, self(), i/count)
75+
LiveAdmin.PubSub.broadcast(session.id, {:job, %{pid: self(), progress: i/count, label: "Regenerating passwords"}})
7676
end)
7777

7878
{:ok, "updated"}

lib/live_admin/components/container.ex

+31-21
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ defmodule LiveAdmin.Components.Container do
22
use Phoenix.LiveView
33
use PhoenixHTMLHelpers
44

5+
require Logger
6+
57
import LiveAdmin,
68
only: [
79
resource_title: 2,
@@ -18,15 +20,12 @@ defmodule LiveAdmin.Components.Container do
1820
alias Phoenix.LiveView.JS
1921

2022
@impl true
21-
def mount(_params, %{"session_id" => session_id}, socket) do
23+
def mount(_params, _session, socket) do
2224
socket =
2325
assign(socket, loading: !connected?(socket), jobs: [])
2426

2527
if connected?(socket) do
2628
Process.send_after(self(), :clear_flash, 1000)
27-
28-
:ok = Phoenix.PubSub.subscribe(LiveAdmin.PubSub, "session:#{session_id}")
29-
:ok = Phoenix.PubSub.subscribe(LiveAdmin.PubSub, "all")
3029
end
3130

3231
{:ok, socket}
@@ -115,34 +114,45 @@ defmodule LiveAdmin.Components.Container do
115114
try do
116115
case apply(m, f, [Resource.query(resource, search, config) | args]) do
117116
{:ok, message} ->
118-
LiveAdmin.Notifier.announce(
119-
session,
120-
trans("Task %{name} succeeded: '%{message}'",
121-
inter: [name: name, message: message]
122-
),
123-
type: :success
117+
LiveAdmin.PubSub.broadcast(
118+
session.id,
119+
{:announce,
120+
%{
121+
message:
122+
trans("Task %{name} succeeded: '%{message}'",
123+
inter: [name: name, message: message]
124+
)
125+
}, type: :success}
124126
)
125127

126128
{:error, message} ->
127-
LiveAdmin.Notifier.announce(
128-
session,
129-
trans("Task %{name} failed: '%{message}'", inter: [name: name, message: message]),
130-
type: :error
129+
LiveAdmin.PubSub.broadcast(
130+
session.id,
131+
{:announce,
132+
%{
133+
message:
134+
trans("Task %{name} failed: '%{message}'",
135+
inter: [name: name, message: message]
136+
),
137+
type: :error
138+
}}
131139
)
132140
end
133141
rescue
134-
_ ->
135-
LiveAdmin.Notifier.announce(
136-
session,
137-
trans("Task %{name} failed", inter: [name: name]),
138-
type: :error
142+
error ->
143+
Logger.error(inspect(error))
144+
145+
LiveAdmin.PubSub.broadcast(
146+
session.id,
147+
{:announce,
148+
%{message: trans("Task %{name} failed", inter: [name: name]), type: :error}}
139149
)
140150
after
141-
LiveAdmin.Notifier.job(session, self(), 1)
151+
LiveAdmin.PubSub.broadcast(session.id, {:job, %{pid: self(), progress: 1}})
142152
end
143153
end)
144154

145-
LiveAdmin.Notifier.job(session, task.pid, 0, label: name)
155+
LiveAdmin.PubSub.broadcast(session.id, {:job, %{pid: task.pid, progress: 0, label: "name"}})
146156

147157
{:noreply, push_redirect(socket, to: route_with_params(socket.assigns))}
148158
end

lib/live_admin/components/nav/jobs.ex

+23-17
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ defmodule LiveAdmin.Components.Nav.Jobs do
66
@impl true
77
def mount(_, %{"session_id" => session_id}, socket) do
88
if connected?(socket) do
9-
:ok = Phoenix.PubSub.subscribe(LiveAdmin.PubSub, "session:#{session_id}")
10-
:ok = Phoenix.PubSub.subscribe(LiveAdmin.PubSub, "all")
9+
:ok = LiveAdmin.PubSub.subscribe(session_id)
10+
:ok = LiveAdmin.PubSub.subscribe()
1111
end
1212

1313
{:ok, assign(socket, jobs: []), layout: false}
@@ -26,34 +26,40 @@ defmodule LiveAdmin.Components.Nav.Jobs do
2626
end
2727

2828
@impl true
29-
def handle_info(info = {:announce, message, type}, socket) do
29+
def handle_info(info = {:announce, %{message: message, type: type}}, socket) do
3030
Logger.debug("ANNOUNCE: #{inspect(info)}")
3131
{:noreply, push_event(socket, type, %{msg: message})}
3232
end
3333

3434
@impl true
35-
def handle_info({:job, pid, :start, label}, socket) do
36-
Process.monitor(pid)
37-
38-
socket = update(socket, :jobs, fn jobs -> [{pid, label, 0.0} | jobs] end)
35+
def handle_info({:job, %{pid: pid, progress: progress}}, socket)
36+
when progress >= 1 do
37+
Process.send_after(self(), {:remove_job, pid}, 1500)
3938

40-
{:noreply, socket}
39+
{:noreply, set_progress(socket, pid, 1.0)}
4140
end
4241

4342
@impl true
44-
def handle_info({:job, pid, :progress, progress}, socket) do
45-
socket = set_progress(socket, pid, progress)
43+
def handle_info({:job, job = %{pid: pid, progress: progress}}, socket) do
44+
socket =
45+
update(socket, :jobs, fn jobs ->
46+
jobs
47+
|> Enum.find_index(fn {job_pid, _, _} -> job_pid == pid end)
48+
|> case do
49+
nil ->
50+
Process.monitor(pid)
51+
[{pid, Map.fetch!(job, :label), 0.0} | jobs]
52+
53+
i ->
54+
List.update_at(jobs, i, fn {pid, job_label, _} ->
55+
{pid, Map.get(job, :label, job_label), progress}
56+
end)
57+
end
58+
end)
4659

4760
{:noreply, socket}
4861
end
4962

50-
@impl true
51-
def handle_info({:job, pid, :complete}, socket) do
52-
Process.send_after(self(), {:remove_job, pid}, 1500)
53-
54-
{:noreply, set_progress(socket, pid, 1.0)}
55-
end
56-
5763
@impl true
5864
def handle_info({:remove_job, pid}, socket) do
5965
socket =

lib/live_admin/components/resource/index.ex

+7-4
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,7 @@ defmodule LiveAdmin.Components.Container.Index do
426426
fn ->
427427
pid = self()
428428

429-
LiveAdmin.Notifier.job(session, pid, 0, label: label)
429+
LiveAdmin.PubSub.broadcast(session.id, {:job, %{pid: pid, progress: 0, label: label}})
430430

431431
records = Resource.all(ids, resource, prefix, repo)
432432

@@ -442,7 +442,10 @@ defmodule LiveAdmin.Components.Container.Index do
442442
rescue
443443
_ -> failed_count + 1
444444
after
445-
LiveAdmin.Notifier.job(session, pid, (i + 1) / length(records))
445+
LiveAdmin.PubSub.broadcast(
446+
session.id,
447+
{:job, %{pid: pid, progress: (i + 1) / length(records)}}
448+
)
446449
end
447450
end)
448451
|> case do
@@ -464,8 +467,8 @@ defmodule LiveAdmin.Components.Container.Index do
464467
)}
465468
end
466469

467-
LiveAdmin.Notifier.job(session, pid, 1)
468-
LiveAdmin.Notifier.announce(session, message, type: type)
470+
LiveAdmin.PubSub.broadcast(session.id, {:job, %{pid: pid, progress: 1}})
471+
LiveAdmin.PubSub.broadcast(session.id, {:announce, %{message: message, type: type}})
469472
end,
470473
timeout: :infinity
471474
)

lib/live_admin/notifier.ex

-34
This file was deleted.

lib/live_admin/pub_sub.ex

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
defmodule LiveAdmin.PubSub do
2+
@moduledoc """
3+
PubSub system for exchanging messages with LiveAdmin.
4+
5+
Includes the following events:
6+
* :job - Shows progress bar indicating status of any ongoing process. LiveAdmin uses this internally to indicate progress of actions on multiple records and tasks. Metadata consists of `pid`, `progress` float/int, and `label` string.
7+
* :announce - Show temporary message with severity level. Meta consists of `message` string, and `type` (`:error`, `:success`, or `:info`)
8+
9+
Currently just a thin wrapper around Phoenix.PubSub, so its possible to use that directly, but discouraged since that may change.
10+
"""
11+
12+
@type session_id :: String.t()
13+
14+
@spec broadcast(session_id, {atom(), map()}) :: :ok
15+
@spec broadcast({atom(), map()}) :: :ok
16+
@doc """
17+
Notify LiveAdmin of event, consisting of a unique name (either global or scoped to the session, if that is passed) and metadata.
18+
"""
19+
def broadcast(session_id \\ nil, event) do
20+
Phoenix.PubSub.broadcast(
21+
__MODULE__,
22+
if(session_id, do: "session:#{session_id}", else: "all"),
23+
event
24+
)
25+
26+
:ok
27+
end
28+
29+
@spec subscribe(session_id) :: :ok
30+
@spec subscribe() :: :ok
31+
@doc """
32+
Subscribe to LiveAdmin events for a specific session.
33+
"""
34+
def subscribe(session_id), do: Phoenix.PubSub.subscribe(__MODULE__, "session:#{session_id}")
35+
36+
@doc """
37+
Subscribe to *all* LiveAdmin events.
38+
"""
39+
def subscribe(), do: Phoenix.PubSub.subscribe(__MODULE__, "all")
40+
end

0 commit comments

Comments
 (0)