PhoenixKitWeb.Components.Core.IntegrationsUI (phoenix_kit v2.13.9)

Copy Markdown View Source

Shared UI for the integration setup screens — the provider picker, the provider/status header card, a single setup field, and the collapsible setup instructions, plus the small display helpers they need (status badge, relative timestamps, inline markdown).

Extracted so the website-wide integrations pages (Live.Settings.Integrations / IntegrationForm) and the personal pages (Live.Integrations.MyIntegrations / MyIntegrationForm) render the same markup instead of drifting apart. The personal screens use it today; the website screens carry their own equivalents pending a convergence pass.

Summary

Functions

Humanizes a UTC ISO8601 timestamp into a relative phrase like "2 hours ago" / "3 days ago" / "Apr 28 2026". nil/""nil; falls back to the raw string on parse failure.

Maps a connection status string to {daisyUI badge class, label}.

Provider picker — a card grid, one card per provider. Clicking a card pushes event (default "select_provider") with phx-value-provider.

Provider info / status header card. No badge is shown until the connection has actually been saved (name set) — a fresh /new flow has nothing to report yet.

Simple inline markdown: **bold**, [links](url), `code` and {variables}.

A single provider setup field, rendered from the field's :type.

Collapsible provider setup instructions (from the provider definition). open defaults closed; callers pass open={@name == nil} to keep it open during first-time setup.

Functions

format_relative(iso_string)

@spec format_relative(String.t() | nil) :: String.t() | nil

Humanizes a UTC ISO8601 timestamp into a relative phrase like "2 hours ago" / "3 days ago" / "Apr 28 2026". nil/""nil; falls back to the raw string on parse failure.

integration_status_badge(_)

@spec integration_status_badge(String.t() | nil) :: {String.t(), String.t()}

Maps a connection status string to {daisyUI badge class, label}.

provider_picker(assigns)

Provider picker — a card grid, one card per provider. Clicking a card pushes event (default "select_provider") with phx-value-provider.

Attributes

  • providers (:list) (required)
  • event (:string) - Defaults to "select_provider".

provider_status_card(assigns)

Provider info / status header card. No badge is shown until the connection has actually been saved (name set) — a fresh /new flow has nothing to report yet.

Attributes

  • provider (:map) (required)
  • data (:map) (required)
  • name (:string) - Defaults to nil.

render_markdown_inline(text, vars)

@spec render_markdown_inline(String.t(), map() | keyword()) :: String.t()

Simple inline markdown: **bold**, [links](url), `code` and {variables}.

setup_field(assigns)

A single provider setup field, rendered from the field's :type.

Credential-shaped fields stay type="text" on purpose — they're API keys / tokens, not site logins, and type="password" would trigger browsers' password-save heuristics. :select, :textarea and :number render as themselves; anything else falls back to a text input, so a provider that declares a type this component has never heard of still gets a usable field rather than a blank spot in the form.

A :select with no stored value falls to the first option, so a provider should list its default first (that is how the SMTP security / auth / verify_cert fields keep their historical behavior on connections created before they existed).

:password fields never echo a saved secret back into the markup (D011 — it used to round-trip in plain text on every Edit render). Resolution is three-way, in priority order:

  1. typed_value present — the operator just typed this (a dry-run Test re-render, /new flow) — show it verbatim, unmasked.
  2. No typed value, saved_value present, and the field is :password — show an empty input with the same "already configured" placeholder Authorization uses for its OAuth secrets (S009, oauth_secret_placeholder/2 in authorization.ex) — same class of leak, same wording, so an operator doesn't see two phrasings of "a secret is already saved" in the same admin. An empty submit for an untouched password field is already read as "keep the existing credential" on the save side (extract_setup_attrs/2 and its mirror in MyIntegrationForm), so this empty render is exactly what that save path expects.
  3. Otherwise — plain fields, or a :password field with nothing saved yet — show saved_value as before.

Attributes

  • field (:map) (required)
  • typed_value (:string) - Defaults to "".
  • saved_value (:string) - Defaults to "".

setup_instructions(assigns)

Collapsible provider setup instructions (from the provider definition). open defaults closed; callers pass open={@name == nil} to keep it open during first-time setup.

Attributes

  • provider (:map) (required)
  • redirect_uri (:string) - Defaults to nil.
  • open (:boolean) - Defaults to false.