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
Current section
221 Versions
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…