Packages
phoenix_kit
1.7.144
1.7.208
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
Files
Jump to
Current section
Files
lib/phoenix_kit_web/live/settings/integrations.ex
defmodule PhoenixKitWeb.Live.Settings.Integrations do
@moduledoc """
Integrations list page — shows all configured service connections.
Each connection is displayed as a card with status, connected account info,
and quick actions (disconnect, test). An "Add Integration" button links to
the form page for creating new connections.
"""
use PhoenixKitWeb, :live_view
use Gettext, backend: PhoenixKitWeb.Gettext
alias PhoenixKit.Integrations
alias PhoenixKit.Integrations.Events
alias PhoenixKit.Integrations.Providers
alias PhoenixKit.Settings
alias PhoenixKit.Utils.Routes
def mount(_params, _session, socket) do
if connected?(socket), do: Events.subscribe()
project_title = Settings.get_project_title()
socket =
socket
|> assign(:page_title, gettext("Integrations"))
|> assign(:project_title, project_title)
|> assign(:current_path, get_current_path(socket.assigns.current_locale_base))
|> load_connections()
|> assign(:validating, nil)
{:ok, socket}
end
def handle_params(_params, _url, socket) do
{:noreply, socket}
end
# ---------------------------------------------------------------------------
# Events
# ---------------------------------------------------------------------------
def handle_event("disconnect", %{"uuid" => uuid}, socket) do
Integrations.disconnect(uuid, actor_uuid(socket))
{:noreply,
socket
|> put_flash(:info, gettext("Disconnected"))
|> load_connections()}
end
def handle_event("validate_connection", %{"uuid" => uuid}, socket) do
send(self(), {:do_validate, uuid})
{:noreply, assign(socket, :validating, uuid)}
end
def handle_event("remove_connection", %{"uuid" => uuid}, socket) do
case Integrations.remove_connection(uuid, actor_uuid(socket)) do
:ok ->
{:noreply,
socket
|> put_flash(:info, gettext("Connection removed"))
|> load_connections()}
{:error, _} ->
{:noreply, put_flash(socket, :error, gettext("Failed to remove connection"))}
end
end
# ---------------------------------------------------------------------------
# Async validation
# ---------------------------------------------------------------------------
def handle_info({:do_validate, uuid}, socket) do
actor = actor_uuid(socket)
result = Integrations.validate_connection(uuid, actor)
Integrations.record_validation(uuid, result)
{:noreply,
socket
|> assign(:validating, nil)
|> load_connections()}
end
# ---------------------------------------------------------------------------
# PubSub handlers
# ---------------------------------------------------------------------------
def handle_info({:integration_setup_saved, _, _}, socket),
do: {:noreply, load_connections(socket)}
def handle_info({:integration_connected, _, _}, socket),
do: {:noreply, load_connections(socket)}
def handle_info({:integration_disconnected, _}, socket),
do: {:noreply, load_connections(socket)}
def handle_info({:integration_validated, _, _}, socket),
do: {:noreply, load_connections(socket)}
def handle_info({:integration_connection_added, _, _}, socket),
do: {:noreply, load_connections(socket)}
def handle_info({:integration_connection_removed, _, _}, socket),
do: {:noreply, load_connections(socket)}
def handle_info({:integration_connection_renamed, _, _, _}, socket),
do: {:noreply, load_connections(socket)}
# Catch-all to prevent crashes from unexpected messages
def handle_info(_msg, socket), do: {:noreply, socket}
# ---------------------------------------------------------------------------
# Private
# ---------------------------------------------------------------------------
defp load_connections(socket) do
providers = Providers.all()
provider_keys = Enum.map(providers, & &1.key)
providers_by_key = Map.new(providers, &{&1.key, &1})
# Single query for all providers instead of N+1
all_connections = Integrations.load_all_connections(provider_keys)
connections =
Enum.flat_map(providers, fn provider ->
Map.get(all_connections, provider.key, [])
|> Enum.map(fn %{uuid: uuid, name: name, data: data} ->
%{
provider: providers_by_key[provider.key],
uuid: uuid,
name: name,
data: data
}
end)
end)
socket
|> assign(:connections, connections)
|> assign(:provider_names, join_with_and(Enum.map(providers, & &1.name)))
end
# Joins a list of names with commas, using a translated "and" before
# the final item: ["A"] → "A", ["A", "B"] → "A and B",
# ["A", "B", "C"] → "A, B and C". `gettext("and")` is extracted to the
# .pot so each locale can supply its own conjunction.
defp join_with_and([]), do: ""
defp join_with_and([single]), do: single
defp join_with_and(list) do
{init, [last]} = Enum.split(list, -1)
Enum.join(init, ", ") <> " " <> gettext("and") <> " " <> last
end
defp actor_uuid(socket) do
case socket.assigns[:phoenix_kit_current_scope] do
%{user: %{uuid: uuid}} -> uuid
_ -> nil
end
end
defp get_current_path(locale) do
Routes.path("/admin/settings/integrations", locale: locale)
end
defp integration_status_badge("connected"), do: {"badge-success", gettext("Connected")}
defp integration_status_badge("configured"), do: {"badge-warning", gettext("Not tested")}
defp integration_status_badge("disconnected"), do: {"badge-ghost", gettext("Not connected")}
defp integration_status_badge("error"), do: {"badge-error", gettext("Error")}
defp integration_status_badge(_), do: {"badge-ghost", gettext("Not configured")}
end