Packages
phoenix_kit
2.13.13
2.13.13
2.13.12
2.13.11
2.13.10
2.13.9
2.13.8
2.13.7
2.13.6
2.13.5
2.13.4
2.13.3
2.13.2
2.13.1
2.13.0
2.12.1
2.12.0
2.11.0
2.10.0
2.9.0
2.8.1
2.8.0
2.7.0
2.6.0
2.5.0
2.4.0
2.3.0
2.2.0
2.1.0
2.0.1
2.0.0
1.7.236
1.7.235
1.7.234
1.7.233
1.7.232
1.7.231
1.7.230
1.7.229
1.7.228
1.7.227
1.7.226
1.7.225
1.7.224
1.7.223
1.7.222
1.7.221
1.7.220
1.7.219
1.7.218
1.7.217
1.7.216
1.7.215
1.7.214
1.7.213
1.7.212
1.7.211
1.7.210
1.7.209
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.html.heex
<PhoenixKitWeb.Components.LayoutWrapper.app_layout
socket={@socket}
flash={@flash}
phoenix_kit_current_scope={assigns[:phoenix_kit_current_scope]}
page_title={gettext("Integrations")}
page_subtitle={gettext("Connect external services for use across modules")}
current_path={@current_path}
project_title={@project_title}
current_locale={@current_locale}
>
<div class="px-4 py-6">
<%!-- Flash messages --%>
<%!-- Guarded on the report's severity, not on the tier. Guarded on
`status != :dedicated`, a dedicated key whose key store had broken
showed no banner at all — while the fingerprint line below it called
that same key a FALLBACK. --%>
<div :if={@encryption_report.severity != :ok} class="alert alert-warning mb-4">
<.icon name="hero-exclamation-triangle" class="w-5 h-5 shrink-0" />
<div>
<div class="font-semibold">
{encryption_status_title(@encryption_report)}
</div>
<div class="text-sm">
{encryption_status_detail(@encryption_report)}
</div>
</div>
</div>
<%!-- Key fingerprint. Shown for every status, not just the unhealthy ones:
two sites can BOTH be on a healthy dedicated key and still be sharing
it (a copied key file, a cloned environment), and nothing else on this
page would reveal that. Admin-only page by design — see
Encryption.key_fingerprint/0 on why this is not for general users. --%>
<div :if={@encryption_fingerprint} class="text-xs opacity-70 mb-4">
{gettext("Encryption key fingerprint:")}
<code class="font-mono">{elem(@encryption_fingerprint, 0)}</code>
<span class="italic">({elem(@encryption_fingerprint, 1)})</span>
— {gettext(
"another site showing this same fingerprint and the same key state is using the same key"
)}
</div>
<%!-- Connections table --%>
<div :if={@connections != []}>
<.table_default
id="integrations-table"
variant="zebra"
toggleable
items={@connections}
card_title={fn conn -> conn.provider.name end}
card_fields={
fn conn ->
fields = [
%{
label: gettext("Status"),
value:
if(@validating == conn.uuid,
do: gettext("Testing..."),
else: elem(integration_status_badge(conn.data["status"]), 1)
)
}
]
fields =
if conn.name != "default",
do: fields ++ [%{label: gettext("Name"), value: conn.name}],
else: fields
fields =
if conn.data["external_account_id"],
do:
fields ++
[%{label: gettext("Account"), value: conn.data["external_account_id"]}],
else: fields
fields
end
}
>
<:toolbar_title>
<span class="text-sm text-base-content/60">
{length(@connections)} {gettext("connections")}
</span>
</:toolbar_title>
<:toolbar_actions>
<.pk_link
navigate="/admin/settings/integrations/website/new"
class="btn btn-primary btn-sm"
>
<.icon name="hero-plus" class="w-4 h-4" />
{gettext("Add Integration")}
</.pk_link>
</:toolbar_actions>
<:card_header :let={conn}>
<div class="flex items-center gap-2">
<.icon name={conn.provider.icon} class="w-5 h-5" />
<span class="font-medium">{conn.provider.name}</span>
<span :if={conn.name != "default"} class="badge badge-ghost badge-xs">
{conn.name}
</span>
</div>
</:card_header>
<.table_default_header>
<.table_default_row>
<.table_default_header_cell>{gettext("Service")}</.table_default_header_cell>
<.table_default_header_cell>{gettext("Name")}</.table_default_header_cell>
<.table_default_header_cell>{gettext("Account")}</.table_default_header_cell>
<.table_default_header_cell>{gettext("Status")}</.table_default_header_cell>
<.table_default_header_cell>{gettext("Actions")}</.table_default_header_cell>
</.table_default_row>
</.table_default_header>
<.table_default_body>
<.table_default_row
:for={conn <- @connections}
class="relative transform-gpu cursor-pointer"
>
<.table_default_cell>
<.row_link
navigate={
PhoenixKit.Utils.Routes.path(
"/admin/settings/integrations/website/#{conn.uuid}"
)
}
label={conn.provider.name}
/>
<div class="flex items-center gap-2">
<.icon name={conn.provider.icon} class="w-4 h-4 text-base-content/60" />
<span>{conn.provider.name}</span>
</div>
</.table_default_cell>
<.table_default_cell>
{conn.name}
</.table_default_cell>
<.table_default_cell>
<span :if={conn.data["external_account_id"]} class="text-sm">
{conn.data["external_account_id"]}
</span>
<span :if={!conn.data["external_account_id"]} class="text-base-content/30">—</span>
</.table_default_cell>
<.table_default_cell>
<%= if @validating == conn.uuid do %>
<span class="badge badge-sm badge-info gap-1">
<span class="loading loading-spinner loading-xs"></span>
{gettext("Testing...")}
</span>
<% else %>
<% {badge_class, badge_text} = integration_status_badge(conn.data["status"]) %>
<div>
<span class={"badge badge-sm #{badge_class}"}>{badge_text}</span>
<span
:if={conn.data["validation_status"] not in [nil, "", "ok"]}
class={[
"text-xs block mt-0.5",
if(conn.data["status"] == "error", do: "text-error", else: "text-warning")
]}
>
{conn.data["validation_status"]}
</span>
</div>
<% end %>
</.table_default_cell>
<.table_default_cell class="relative z-10">
<.table_row_menu
id={"integration-menu-#{conn.uuid}"}
mode="auto"
label={gettext("Actions")}
>
<.table_row_menu_link
navigate={
PhoenixKit.Utils.Routes.path(
"/admin/settings/integrations/website/#{conn.uuid}"
)
}
icon="hero-pencil"
label={gettext("Configure")}
/>
<.table_row_menu_button
:if={conn.data["status"] in ["connected", "configured", "error"]}
phx-click="validate_connection"
phx-value-uuid={conn.uuid}
icon="hero-signal"
label={gettext("Test Connection")}
/>
<.table_row_menu_divider :if={conn.data["status"] == "connected"} />
<.table_row_menu_button
:if={conn.data["status"] == "connected"}
phx-click="disconnect"
phx-value-uuid={conn.uuid}
icon="hero-link-slash"
label={gettext("Disconnect")}
variant="warning"
data-confirm={gettext("Are you sure you want to disconnect?")}
/>
<.table_row_menu_button
phx-click="remove_connection"
phx-value-uuid={conn.uuid}
icon="hero-trash"
label={gettext("Remove")}
variant="error"
data-confirm={
gettext(
"This integration may be in use by other parts of the system. Remove it permanently?"
)
}
/>
</.table_row_menu>
</.table_default_cell>
</.table_default_row>
</.table_default_body>
<:card_actions :let={conn}>
<.table_row_menu
id={"integration-card-menu-#{conn.uuid}"}
mode="auto"
label={gettext("Actions")}
>
<.table_row_menu_link
navigate={
PhoenixKit.Utils.Routes.path("/admin/settings/integrations/website/#{conn.uuid}")
}
icon="hero-pencil"
label={gettext("Configure")}
/>
<.table_row_menu_button
:if={conn.data["status"] in ["connected", "configured", "error"]}
phx-click="validate_connection"
phx-value-uuid={conn.uuid}
icon="hero-signal"
label={gettext("Test Connection")}
/>
<.table_row_menu_divider :if={conn.data["status"] == "connected"} />
<.table_row_menu_button
:if={conn.data["status"] == "connected"}
phx-click="disconnect"
phx-value-uuid={conn.uuid}
icon="hero-link-slash"
label={gettext("Disconnect")}
variant="warning"
data-confirm={gettext("Disconnect?")}
/>
<.table_row_menu_button
phx-click="remove_connection"
phx-value-uuid={conn.uuid}
icon="hero-trash"
label={gettext("Remove")}
variant="error"
data-confirm={
gettext(
"This integration may be in use by other parts of the system. Remove it permanently?"
)
}
/>
</.table_row_menu>
</:card_actions>
</.table_default>
</div>
<%!-- Empty state --%>
<.empty_state
:if={@connections == []}
icon="hero-link"
title={gettext("No integrations configured")}
description={
gettext("Connect external services like %{providers}.", providers: @provider_names)
}
>
<.pk_link navigate="/admin/settings/integrations/website/new" class="btn btn-primary btn-sm">
<.icon name="hero-plus" class="w-4 h-4" />
{gettext("Add Integration")}
</.pk_link>
</.empty_state>
</div>
</PhoenixKitWeb.Components.LayoutWrapper.app_layout>