Packages
phoenix_kit
1.7.178
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
16
files changed
+484
additions
-50
deletions
unknownCHANGELOG.md
File is too large to be displayed (100 KB limit).
| @@ -1,6 +1,6 @@ | |
| 1 1 | {<<"links">>,[{<<"GitHub">>,<<"https://github.com/BeamLabEU/phoenix_kit">>}]}. |
| 2 2 | {<<"name">>,<<"phoenix_kit">>}. |
| 3 | - {<<"version">>,<<"1.7.177">>}. |
| 3 | + {<<"version">>,<<"1.7.178">>}. |
| 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, |
| @@ -350,6 +350,7 @@ | |
| 350 350 | <<"lib/phoenix_kit/integrations/events.ex">>, |
| 351 351 | <<"lib/phoenix_kit/integrations/providers.ex">>, |
| 352 352 | <<"lib/phoenix_kit/integrations/integrations.ex">>, |
| 353 | + <<"lib/phoenix_kit/integrations/resource_links.ex">>, |
| 353 354 | <<"lib/phoenix_kit/integrations/encryption.ex">>, |
| 354 355 | <<"lib/phoenix_kit/integrations/oauth.ex">>, |
| 355 356 | <<"lib/phoenix_kit/supervisor.ex">>,<<"lib/phoenix_kit/audit_log.ex">>, |
| @@ -1270,12 +1270,23 @@ defmodule PhoenixKit.Integrations do | |
| 1270 1270 | defp log_activity(action, provider, name, metadata, mode, actor_uuid) |
| 1271 1271 | when is_binary(provider) and is_binary(name) do |
| 1272 1272 | if Code.ensure_loaded?(PhoenixKit.Activity) do |
| 1273 | + # Stamp the storage row's uuid so the activity deep-links to the |
| 1274 | + # connection's edit page (via PhoenixKit.Integrations.ResourceLinks). |
| 1275 | + # nil when the row can't be resolved (e.g. a disconnect that removed it) — |
| 1276 | + # the feed still renders, just without a link. |
| 1277 | + resource_uuid = |
| 1278 | + case find_uuid_by_provider_name({provider, name}) do |
| 1279 | + {:ok, uuid} -> uuid |
| 1280 | + _ -> nil |
| 1281 | + end |
| 1282 | + |
| 1273 1283 | PhoenixKit.Activity.log(%{ |
| 1274 1284 | action: action, |
| 1275 1285 | module: "integrations", |
| 1276 1286 | mode: mode, |
| 1277 1287 | actor_uuid: actor_uuid, |
| 1278 1288 | resource_type: "integration", |
| 1289 | + resource_uuid: resource_uuid, |
| 1279 1290 | metadata: |
| 1280 1291 | Map.merge(metadata, %{ |
| 1281 1292 | "provider" => provider, |
| @@ -0,0 +1,58 @@ | |
| 1 | + defmodule PhoenixKit.Integrations.ResourceLinks do |
| 2 | + @moduledoc """ |
| 3 | + Resolves `"integration"` resources to their edit page for deep-linking. |
| 4 | + |
| 5 | + An activity logged against an integration (`resource_type: "integration"`, |
| 6 | + `resource_uuid:` the storage row's uuid) resolves to the connection's edit |
| 7 | + page (`/admin/settings/integrations/:uuid`), titled `provider / name`. |
| 8 | + |
| 9 | + Registered as the `"integration"` handler by `PhoenixKit.ResourceLinks` |
| 10 | + (gated on this module being loaded). Mirrors |
| 11 | + `PhoenixKit.Users.CommentResources` — implements the same |
| 12 | + `resolve_comment_resources/1` contract and returns a **raw** phoenix_kit path |
| 13 | + (`Routes.path/1` is applied once at render). |
| 14 | + """ |
| 15 | + |
| 16 | + alias PhoenixKit.Integrations |
| 17 | + |
| 18 | + @spec resolve_comment_resources([binary()]) :: %{binary() => map()} |
| 19 | + def resolve_comment_resources(resource_uuids) when is_list(resource_uuids) do |
| 20 | + resource_uuids |
| 21 | + |> Enum.uniq() |
| 22 | + |> Enum.reduce(%{}, fn uuid, acc -> |
| 23 | + case info_for(uuid) do |
| 24 | + nil -> acc |
| 25 | + info -> Map.put(acc, uuid, info) |
| 26 | + end |
| 27 | + end) |
| 28 | + rescue |
| 29 | + _ -> %{} |
| 30 | + end |
| 31 | + |
| 32 | + # Raw path — the caller applies Routes.path/1 (prefix + locale) at render. |
| 33 | + # The title lookup is best-effort: a transient settings error falls back to a |
| 34 | + # generic label rather than dropping the (still-valid) deep-link. |
| 35 | + defp info_for(uuid) when is_binary(uuid) and uuid != "" do |
| 36 | + %{title: title_for(uuid), path: "/admin/settings/integrations/#{uuid}"} |
| 37 | + end |
| 38 | + |
| 39 | + defp info_for(_), do: nil |
| 40 | + |
| 41 | + defp title_for(uuid) do |
| 42 | + case Integrations.get_integration_by_uuid(uuid) do |
| 43 | + {:ok, %{provider: provider, name: name}} -> connection_title(provider, name) |
| 44 | + _ -> "Integration" |
| 45 | + end |
| 46 | + rescue |
| 47 | + _ -> "Integration" |
| 48 | + end |
| 49 | + |
| 50 | + defp connection_title(provider, name) do |
| 51 | + case {to_string(provider), to_string(name)} do |
| 52 | + {"", ""} -> "Integration" |
| 53 | + {p, ""} -> p |
| 54 | + {"", n} -> n |
| 55 | + {p, n} -> "#{p} / #{n}" |
| 56 | + end |
| 57 | + end |
| 58 | + end |
| @@ -150,6 +150,43 @@ defmodule PhoenixKit.Module do | |
| 150 150 | """ |
| 151 151 | @callback notification_types() :: [map()] |
| 152 152 | |
| 153 | + @doc """ |
| 154 | + Declares how this module's resource types deep-link to their pages. |
| 155 | + |
| 156 | + Lets the activity feed, notifications, and the comments moderation admin turn |
| 157 | + a `(resource_type, resource_uuid)` pair from *this* module into a clickable |
| 158 | + link to the underlying record — with zero host configuration. Returns a map of |
| 159 | + `resource_type => resolver`, where a resolver is either: |
| 160 | + |
| 161 | + * **a module** implementing `resolve_comment_resources/1` (the same contract |
| 162 | + core's `"user"`/`"file"`/`"post"` handlers use) — for rich resolution with |
| 163 | + a title and optional thumbnail. Return `%{uuid => %{title:, path:}}` with a |
| 164 | + **raw** phoenix_kit path (`Routes.path/1` is applied once at render). |
| 165 | + |
| 166 | + * **a path-template string** — the no-code shortcut, e.g. |
| 167 | + `"/admin/widgets/:uuid"`. Placeholders: `:uuid` and `:metadata.<key>` |
| 168 | + (pulled from the activity/comment metadata). Treated as an internal |
| 169 | + phoenix_kit route (SPA-navigated, prefix/locale applied). Use the map form |
| 170 | + `%{"path" => "...", "title" => ":metadata.name"}` to set a display title. |
| 171 | + |
| 172 | + ## Examples |
| 173 | + |
| 174 | + # No-code: a raw admin route with a uuid segment |
| 175 | + def resource_links, do: %{"widget" => "/admin/widgets/:uuid"} |
| 176 | + |
| 177 | + # Titled template |
| 178 | + def resource_links, |
| 179 | + do: %{"widget" => %{"path" => "/admin/widgets/:uuid", "title" => ":metadata.name"}} |
| 180 | + |
| 181 | + # Rich: point at a resolver module (title + thumbnail via a DB lookup) |
| 182 | + def resource_links, do: %{"widget" => MyApp.WidgetLinks} |
| 183 | + |
| 184 | + Merges with core's built-in handlers and the host's `comment_resource_paths` |
| 185 | + setting via `PhoenixKit.ResourceLinks`. Modules with no linkable resources can |
| 186 | + skip this callback — the default is `%{}`. |
| 187 | + """ |
| 188 | + @callback resource_links() :: %{optional(String.t()) => module() | String.t() | map()} |
| 189 | + |
| 153 190 | @doc """ |
| 154 191 | Returns Tailwind CSS source roots for scanning. |
| 155 192 | |
| @@ -329,6 +366,7 @@ defmodule PhoenixKit.Module do | |
| 329 366 | required_integrations: 0, |
| 330 367 | integration_providers: 0, |
| 331 368 | notification_types: 0, |
| 369 | + resource_links: 0, |
| 332 370 | css_sources: 0, |
| 333 371 | js_sources: 0, |
| 334 372 | sitemap_sources: 0, |
| @@ -385,6 +423,9 @@ defmodule PhoenixKit.Module do | |
| 385 423 | @impl PhoenixKit.Module |
| 386 424 | def notification_types, do: [] |
| 387 425 | |
| 426 | + @impl PhoenixKit.Module |
| 427 | + def resource_links, do: %{} |
| 428 | + |
| 388 429 | @impl PhoenixKit.Module |
| 389 430 | def css_sources, do: [] |
| 390 431 | |
| @@ -413,6 +454,7 @@ defmodule PhoenixKit.Module do | |
| 413 454 | required_integrations: 0, |
| 414 455 | integration_providers: 0, |
| 415 456 | notification_types: 0, |
| 457 | + resource_links: 0, |
| 416 458 | css_sources: 0, |
| 417 459 | js_sources: 0, |
| 418 460 | sitemap_sources: 0, |
Loading more files…