Packages

phoenix_kit

1.7.101
1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

221 Versions

Jump to

Compare versions

24 files changed
+1472 additions
-30 deletions
  @@ -1,3 +1,18 @@
1 + ## 1.7.101 - 2026-04-24
2 +
3 + ### Added
4 + - **Notifications module** — per-user inbox driven by the activity log. When `PhoenixKit.Activity.log/1` records an entry with `target_uuid != actor_uuid`, a row is inserted into `phoenix_kit_notifications` for the target user. Independent `seen_at` / `dismissed_at` per row, per-user PubSub topic (`"phoenix_kit:notifications:<user_uuid>"`), global kill-switch via `notifications_enabled` setting (default `"true"`). Admins still audit via `/admin/activity` and don't receive notifications (PR #505)
5 + - V104 migration: `phoenix_kit_notifications` with UUIDv7 PK, FKs to `phoenix_kit_activities` and `phoenix_kit_users` (both `ON DELETE CASCADE`), unique `(activity_uuid, recipient_uuid)` index, partial `(recipient_uuid, inserted_at DESC) WHERE dismissed_at IS NULL` index for the inbox read path
6 + - `PhoenixKit.Notifications` public API: `maybe_create_from_activity/1`, `list_for_user/2`, `recent_for_user/2`, `count_unread/1`, `mark_seen/2`, `mark_all_seen/1`, `dismiss/2`, `dismiss_all/1`, `get_notification/2`, `enabled?/0`, `retention_days/0`, `prune/1`
7 + - `PhoenixKit.Notifications.Render.render/1` — maps action → `%{icon, text, link, actor_uuid}`; honors metadata overrides (`notification_text`, `notification_icon`, `notification_link`) before falling back to the action lookup
8 + - `PhoenixKit.Notifications.Types` registry — three core types (`account`, `posts`, `comments`) plus extension point for external modules via the new optional `notification_types/0` callback on `PhoenixKit.Module`
9 + - `PhoenixKit.Notifications.Prefs` — per-user preferences persisted in `custom_fields.notification_preferences` (reuses V18 JSONB column; no migration). Fail-open on any ambiguity
10 + - `PhoenixKit.Notifications.PruneWorker` — daily Oban cron at `"0 4 * * *"`; retention via `notifications_retention_days` (falls back to `activity_retention_days`, default 90)
11 + - `PhoenixKitWeb.Live.NotificationsBell` — sticky nested LiveView for the bell + dropdown. Not mounted by default; parent apps render it where they have a user-facing header via `Phoenix.Component.live_render(..., sticky: true, session: %{"user_uuid" => ...})`. Badge + recent list refresh live via PubSub
12 + - Notification preferences section in `PhoenixKitWeb.Live.Components.UserSettings` — one toggle per registered type; unknown submitted keys dropped at the call site
13 + - `notifications_enabled` toggle on `/admin/settings`
14 + - Arity-2 `dynamic_children_fn` for admin sidebar tabs — callbacks can now be `(scope, locale -> [tab])` in addition to the existing `(scope -> [tab])`. Backwards-compatible extension: the sidebar dispatches on arity, every existing 1-arity callback keeps working unchanged. Lets plugins render locale-aware child labels without reading `Gettext.get_locale/1` at render time (PR #506)
15 +
1 16 ## 1.7.100 - 2026-04-22
2 17
3 18 ### Added
  @@ -1,6 +1,6 @@
1 1 {<<"links">>,[{<<"GitHub">>,<<"https://github.com/BeamLabEU/phoenix_kit">>}]}.
2 2 {<<"name">>,<<"phoenix_kit">>}.
3 - {<<"version">>,<<"1.7.100">>}.
3 + {<<"version">>,<<"1.7.101">>}.
4 4 {<<"description">>,
5 5 <<65,32,102,111,117,110,100,97,116,105,111,110,32,102,111,114,32,98,117,105,
6 6 108,100,105,110,103,32,69,108,105,120,105,114,32,80,104,111,101,110,105,
  @@ -193,6 +193,7 @@
193 193 <<"lib/phoenix_kit_web/components/core/aws_credentials_verify.ex">>,
194 194 <<"lib/phoenix_kit_web/components/core/dev_notice.ex">>,
195 195 <<"lib/phoenix_kit_web/components/core/module_card.ex">>,
196 + <<"lib/phoenix_kit_web/components/core/phoenix_kit_favicon.ex">>,
196 197 <<"lib/phoenix_kit_web/components/core/form_field_error.ex">>,
197 198 <<"lib/phoenix_kit_web/components/core/button.ex">>,
198 199 <<"lib/phoenix_kit_web/components/core/file_upload.ex">>,
  @@ -285,6 +286,7 @@
285 286 <<"lib/phoenix_kit_web/live/activity/show.ex">>,
286 287 <<"lib/phoenix_kit_web/live/activity/index.html.heex">>,
287 288 <<"lib/phoenix_kit_web/live/dashboard.ex">>,
289 + <<"lib/phoenix_kit_web/live/notifications_bell.ex">>,
288 290 <<"lib/phoenix_kit_web/live/modules">>,
289 291 <<"lib/phoenix_kit_web/live/modules/jobs">>,
290 292 <<"lib/phoenix_kit_web/live/modules/jobs/index.html.heex">>,
  @@ -362,6 +364,14 @@
362 364 <<"lib/phoenix_kit/supervisor.ex">>,<<"lib/phoenix_kit/audit_log.ex">>,
363 365 <<"lib/phoenix_kit/theme_config.ex">>,<<"lib/phoenix_kit/audit_log">>,
364 366 <<"lib/phoenix_kit/audit_log/entry.ex">>,<<"lib/phoenix_kit/migration.ex">>,
367 + <<"lib/phoenix_kit/notifications">>,
368 + <<"lib/phoenix_kit/notifications/notifications.ex">>,
369 + <<"lib/phoenix_kit/notifications/types.ex">>,
370 + <<"lib/phoenix_kit/notifications/prefs.ex">>,
371 + <<"lib/phoenix_kit/notifications/notification.ex">>,
372 + <<"lib/phoenix_kit/notifications/render.ex">>,
373 + <<"lib/phoenix_kit/notifications/events.ex">>,
374 + <<"lib/phoenix_kit/notifications/prune_worker.ex">>,
365 375 <<"lib/phoenix_kit/scheduled_jobs">>,
366 376 <<"lib/phoenix_kit/scheduled_jobs/handler.ex">>,
367 377 <<"lib/phoenix_kit/scheduled_jobs/workers">>,
  @@ -456,6 +466,7 @@
456 466 <<"lib/phoenix_kit/migrations/postgres/v53.ex">>,
457 467 <<"lib/phoenix_kit/migrations/postgres/v23.ex">>,
458 468 <<"lib/phoenix_kit/migrations/postgres/v34.ex">>,
469 + <<"lib/phoenix_kit/migrations/postgres/v104.ex">>,
459 470 <<"lib/phoenix_kit/migrations/postgres/v44.ex">>,
460 471 <<"lib/phoenix_kit/migrations/postgres/v36.ex">>,
461 472 <<"lib/phoenix_kit/migrations/postgres/v69.ex">>,
  @@ -52,6 +52,7 @@ defmodule PhoenixKit.Activity do
52 52 case %Entry{} |> Entry.changeset(attrs) |> repo().insert() do
53 53 {:ok, entry} ->
54 54 broadcast_activity(entry)
55 + maybe_notify(entry)
55 56 {:ok, entry}
56 57
57 58 {:error, changeset} ->
  @@ -64,6 +65,17 @@ defmodule PhoenixKit.Activity do
64 65 {:error, e}
65 66 end
66 67
68 + # Fan out to per-user notifications. Guarded with `Code.ensure_loaded?` so
69 + # the core Activity module keeps working if the Notifications module is
70 + # ever stripped out or not yet compiled during recompile cascades.
71 + defp maybe_notify(entry) do
72 + if Code.ensure_loaded?(PhoenixKit.Notifications) do
73 + PhoenixKit.Notifications.maybe_create_from_activity(entry)
74 + end
75 + rescue
76 + e -> Logger.warning("Notifications fan-out failed: #{inspect(e)}")
77 + end
78 +
67 79 @doc """
68 80 Logs a user change with automatic from/to diff extraction from a changeset.
  @@ -112,7 +112,15 @@ defmodule PhoenixKit.Dashboard.Tab do
112 112
113 113 @type level :: :user | :admin | :all
114 114
115 - @type dynamic_children_fn :: (map() -> [t()]) | nil
115 + # `dynamic_children` may have arity 1 (receives scope) or arity 2 (receives scope
116 + # and the current locale). The 2-arity variant lets modules render locale-aware
117 + # children (e.g. translated tab labels) without having to fall back on
118 + # `Gettext.get_locale/1` at render time. The sidebar dispatches on arity; both
119 + # forms are supported for backwards compatibility.
120 + @type dynamic_children_fn ::
121 + (map() -> [t()])
122 + | (map(), String.t() | nil -> [t()])
123 + | nil
116 124
117 125 @type t :: %__MODULE__{
118 126 id: atom(),
  @@ -126,7 +126,8 @@ defmodule PhoenixKit.Install.ObanConfig do
126 126 {Oban.Plugins.Cron,
127 127 crontab: [
128 128 {"* * * * *", PhoenixKit.ScheduledJobs.Workers.ProcessScheduledJobsWorker},
129 - {"0 3 * * *", PhoenixKit.Modules.Storage.Workers.PruneTrashJob}
129 + {"0 3 * * *", PhoenixKit.Modules.Storage.Workers.PruneTrashJob},
130 + {"0 4 * * *", PhoenixKit.Notifications.PruneWorker}
130 131 ]}
131 132 ]
132 133 """
  @@ -726,7 +727,8 @@ defmodule PhoenixKit.Install.ObanConfig do
726 727 {Oban.Plugins.Cron,
727 728 crontab: [
728 729 {"* * * * *", PhoenixKit.ScheduledJobs.Workers.ProcessScheduledJobsWorker},
729 - {"0 3 * * *", PhoenixKit.Modules.Storage.Workers.PruneTrashJob}
730 + {"0 3 * * *", PhoenixKit.Modules.Storage.Workers.PruneTrashJob},
731 + {"0 4 * * *", PhoenixKit.Notifications.PruneWorker}
730 732 ]}
731 733 ]
Loading more files…