mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
chore(portal): Misc sign in UX fixes (#3564)
Fixes #3389 Fixes #3331 Will need #3433 to merge for the entra logo to show up, but this will fail gracefully if it lands before then. <img width="537" alt="Screenshot 2024-02-05 at 5 36 17 AM" src="https://github.com/firezone/firezone/assets/167144/90967150-e048-47ef-99cd-2f758021d017"> <img width="543" alt="Screenshot 2024-02-05 at 5 33 30 AM" src="https://github.com/firezone/firezone/assets/167144/9683488a-ec4e-47dd-bdbc-e95fcf0bc08c"> <img width="528" alt="Screenshot 2024-02-05 at 5 33 13 AM" src="https://github.com/firezone/firezone/assets/167144/fce5487d-3dd5-4b21-bb20-5097ba7055be">
This commit is contained in:
@@ -1134,4 +1134,32 @@ defmodule Web.CoreComponents do
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Renders a logo appropriate for the given provider.
|
||||
|
||||
<.provider_icon adapter={:google_workspace} class="w-5 h-5 mr-2" />
|
||||
"""
|
||||
attr :adapter, :atom, required: false
|
||||
attr :rest, :global
|
||||
|
||||
def provider_icon(%{adapter: :google_workspace} = assigns) do
|
||||
~H"""
|
||||
<img src={~p"/images/google-logo.svg"} alt="Google Workspace Logo" {@rest} />
|
||||
"""
|
||||
end
|
||||
|
||||
def provider_icon(%{adapter: :openid_connect} = assigns) do
|
||||
~H"""
|
||||
<img src={~p"/images/openid-logo.svg"} alt="OpenID Connect Logo" {@rest} />
|
||||
"""
|
||||
end
|
||||
|
||||
def provider_icon(%{adapter: :microsoft_entra} = assigns) do
|
||||
~H"""
|
||||
<img src={~p"/images/entra-logo.svg"} alt="Microsoft Entra Logo" {@rest} />
|
||||
"""
|
||||
end
|
||||
|
||||
def provider_icon(assigns), do: ~H""
|
||||
end
|
||||
|
||||
@@ -211,7 +211,7 @@ defmodule Web.FormComponents do
|
||||
<div phx-feedback-for={@name}>
|
||||
<.label :if={not is_nil(@label)} for={@id}><%= @label %></.label>
|
||||
<div class={[
|
||||
"flex items-center",
|
||||
"flex",
|
||||
"text-sm text-neutral-900 bg-neutral-50",
|
||||
"border-neutral-300 border rounded",
|
||||
"w-full",
|
||||
@@ -220,19 +220,16 @@ defmodule Web.FormComponents do
|
||||
"peer-disabled:bg-neutral-50 peer-disabled:text-neutral-500 peer-disabled:border-neutral-200 peer-disabled:shadow-none",
|
||||
@errors != [] && "border-rose-400"
|
||||
]}>
|
||||
<div
|
||||
<span
|
||||
class={[
|
||||
"-mr-5",
|
||||
"select-none cursor-text",
|
||||
"text-neutral-500",
|
||||
"p-2.5 block"
|
||||
"bg-neutral-200 whitespace-nowrap rounded-e-0 rounded-s inline-flex items-center px-3"
|
||||
]}
|
||||
id={"#{@id}-prefix"}
|
||||
phx-hook="Refocus"
|
||||
data-refocus={@id}
|
||||
>
|
||||
<%= @prefix %>
|
||||
</div>
|
||||
</span>
|
||||
<input
|
||||
type={@type}
|
||||
name={@name}
|
||||
@@ -240,7 +237,7 @@ defmodule Web.FormComponents do
|
||||
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
|
||||
class={[
|
||||
"text-sm text-neutral-900 bg-transparent border-0",
|
||||
"p-2.5 block w-full",
|
||||
"flex-1 min-w-0 p-2.5 block w-full",
|
||||
"focus:outline-none focus:border-0 focus:ring-0"
|
||||
]}
|
||||
{@rest}
|
||||
@@ -472,6 +469,15 @@ defmodule Web.FormComponents do
|
||||
]
|
||||
end
|
||||
|
||||
defp button_style("info") do
|
||||
button_style() ++
|
||||
[
|
||||
"text-neutral-900",
|
||||
"border border-neutral-200",
|
||||
"hover:bg-neutral-100 hover:text-neutral-900"
|
||||
]
|
||||
end
|
||||
|
||||
defp button_style(_style) do
|
||||
button_style() ++
|
||||
[
|
||||
|
||||
@@ -40,7 +40,7 @@ defmodule Web.HomeHTML do
|
||||
required
|
||||
autofocus
|
||||
/>
|
||||
<p>As shown in your "Welcome to Firezone" email</p>
|
||||
<p>Your account ID can be found in your welcome email.</p>
|
||||
|
||||
<.button class="w-full">
|
||||
Go to Sign In page
|
||||
|
||||
@@ -38,6 +38,10 @@ defmodule Web.Resources.Index do
|
||||
<:title>
|
||||
Resources
|
||||
</:title>
|
||||
<:help>
|
||||
Resources define the subnets, hosts, and applications for which you want to manage access. You can manage resources per site
|
||||
in the <.link navigate={~p"/#{@account}/sites"} class={link_style()}>sites</.link> section.
|
||||
</:help>
|
||||
<:action>
|
||||
<.add_button
|
||||
:if={Domain.Config.multi_site_resources_enabled?()}
|
||||
@@ -50,7 +54,7 @@ defmodule Web.Resources.Index do
|
||||
<div class="bg-white overflow-hidden">
|
||||
<.table id="resources" rows={@resources} row_id={&"resource-#{&1.id}"}>
|
||||
<:col :let={resource} label="NAME">
|
||||
<.link navigate={~p"/#{@account}/resources/#{resource.id}"} class={[link_style()]}>
|
||||
<.link navigate={~p"/#{@account}/resources/#{resource.id}"} class={link_style()}>
|
||||
<%= resource.name %>
|
||||
</.link>
|
||||
</:col>
|
||||
@@ -63,7 +67,7 @@ defmodule Web.Resources.Index do
|
||||
<.link
|
||||
:for={gateway_group <- resource.gateway_groups}
|
||||
navigate={~p"/#{@account}/sites/#{gateway_group}"}
|
||||
class={[link_style()]}
|
||||
class={link_style()}
|
||||
>
|
||||
<.badge type="info">
|
||||
<%= gateway_group.name %>
|
||||
|
||||
@@ -75,7 +75,7 @@ defmodule Web.Settings.IdentityProviders.New do
|
||||
adapter={@adapter}
|
||||
account={@account}
|
||||
name="OpenID Connect"
|
||||
description="Authenticate users with a universal OpenID Connect adapter and synchronize users with just-in-time (JIT) provisioning."
|
||||
description="Authenticate users with a universal OpenID Connect adapter and manager users and groups manually."
|
||||
/>
|
||||
"""
|
||||
end
|
||||
@@ -103,6 +103,7 @@ defmodule Web.Settings.IdentityProviders.New do
|
||||
class={~w[ w-4 h-4 border-neutral-300 ]}
|
||||
required
|
||||
/>
|
||||
<.provider_icon adapter={@adapter} class="w-8 h-8 ml-4" />
|
||||
<label for={"idp-option-#{@adapter}"} class="block ml-2 text-lg text-neutral-900">
|
||||
<%= @name %>
|
||||
</label>
|
||||
|
||||
@@ -51,7 +51,7 @@ defmodule Web.SignIn do
|
||||
<div class="p-6 space-y-4 lg:space-y-6 sm:p-8">
|
||||
<h1 class="text-xl text-center leading-tight tracking-tight text-neutral-900 sm:text-2xl">
|
||||
<span>
|
||||
Sign into <%= @account.name %>
|
||||
Sign in to <%= @account.name %>
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
@@ -200,27 +200,23 @@ defmodule Web.SignIn do
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
/>
|
||||
|
||||
<:actions>
|
||||
<.button phx-disable-with="Sending..." class="w-full">
|
||||
Request sign in token
|
||||
</.button>
|
||||
</:actions>
|
||||
<.button phx-disable-with="Sending..." class="w-full" style="info">
|
||||
Request sign in token
|
||||
</.button>
|
||||
</.simple_form>
|
||||
"""
|
||||
end
|
||||
|
||||
def openid_connect_button(assigns) do
|
||||
~H"""
|
||||
<a href={~p"/#{@account}/sign_in/providers/#{@provider}/redirect?#{@params}"} class={~w[
|
||||
w-full inline-flex items-center justify-center py-2.5 px-5
|
||||
bg-white rounded
|
||||
text-sm text-neutral-900
|
||||
border border-neutral-200
|
||||
hover:bg-neutral-100 hover:text-neutral-900
|
||||
]}>
|
||||
Sign in with <%= @provider.name %>
|
||||
</a>
|
||||
<.button
|
||||
navigate={~p"/#{@account}/sign_in/providers/#{@provider}/redirect?#{@params}"}
|
||||
class="w-full space-x-1"
|
||||
style="info"
|
||||
>
|
||||
<.provider_icon adapter={@provider.adapter} class="w-5 h-5 mr-2" /> Sign in with
|
||||
<strong><%= @provider.name %></strong>
|
||||
</.button>
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
@@ -44,8 +44,9 @@ defmodule Web.SignIn.Email do
|
||||
|
||||
<div>
|
||||
<p>
|
||||
Should the provided email be registered, a sign in token has been sent to your email account.
|
||||
Please copy and paste this into the form below to proceed with your login.
|
||||
If <strong><%= @provider_identifier %></strong> is registered, a sign in token has
|
||||
been sent to that email. Please copy and paste this into the form below to proceed
|
||||
with your login.
|
||||
</p>
|
||||
<form
|
||||
id="verify-sign-in-token"
|
||||
|
||||
@@ -83,7 +83,7 @@ defmodule Web.Sites.Show do
|
||||
<:action :if={is_nil(@group.deleted_at)}>
|
||||
<.delete_button
|
||||
phx-click="revoke_all_tokens"
|
||||
data-confirm="Are you sure you want to revoke all tokens? This will immediately sign the actor out of all clients."
|
||||
data-confirm="Are you sure you want to revoke all tokens? This will immediately disconnect all gateways in this site."
|
||||
>
|
||||
Revoke All Tokens
|
||||
</.delete_button>
|
||||
@@ -139,7 +139,7 @@ defmodule Web.Sites.Show do
|
||||
</.add_button>
|
||||
</:action>
|
||||
<:help>
|
||||
Resources are the endpoints that you want to make available to your clients.
|
||||
Resources are the subnets, hosts, and applications that you wish to manage access to.
|
||||
</:help>
|
||||
<:content>
|
||||
<div class="relative overflow-x-auto">
|
||||
|
||||
9
elixir/apps/web/priv/static/images/entra-logo.svg
Normal file
9
elixir/apps/web/priv/static/images/entra-logo.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg id="uuid-f8d4d392-7c12-4bd9-baff-66fbf7814b91" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
|
||||
<path d="m3.802,14.032c.388.242,1.033.511,1.715.511.621,0,1.198-.18,1.676-.487,0,0,.001,0,.002-.001l1.805-1.128v4.073c-.286,0-.574-.078-.824-.234l-4.374-2.734Z" fill="#225086"/>
|
||||
<path d="m7.853,1.507L.353,9.967c-.579.654-.428,1.642.323,2.111,0,0,2.776,1.735,3.126,1.954.388.242,1.033.511,1.715.511.621,0,1.198-.18,1.676-.487,0,0,.001,0,.002-.001l1.805-1.128-4.364-2.728,4.365-4.924V1s0,0,0,0c-.424,0-.847.169-1.147.507Z" fill="#6df"/>
|
||||
<polygon points="4.636 10.199 4.688 10.231 9 12.927 9.001 12.927 9.001 12.927 9.001 5.276 9 5.275 4.636 10.199" fill="#cbf8ff"/>
|
||||
<path d="m17.324,12.078c.751-.469.902-1.457.323-2.111l-4.921-5.551c-.397-.185-.842-.291-1.313-.291-.925,0-1.752.399-2.302,1.026l-.109.123h0s4.364,4.924,4.364,4.924h0s0,0,0,0l-4.365,2.728v4.073c.287,0,.573-.078.823-.234l7.5-4.688Z" fill="#074793"/>
|
||||
<path d="m9.001,1v4.275s.109-.123.109-.123c.55-.627,1.377-1.026,2.302-1.026.472,0,.916.107,1.313.291l-2.579-2.909c-.299-.338-.723-.507-1.146-.507Z" fill="#0294e4"/>
|
||||
<polygon points="13.365 10.199 13.365 10.199 13.365 10.199 9.001 5.276 9.001 12.926 13.365 10.199" fill="#96bcc2"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
elixir/apps/web/priv/static/images/google-logo.svg
Normal file
1
elixir/apps/web/priv/static/images/google-logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/><path d="M1 1h22v22H1z" fill="none"/></svg>
|
||||
|
After Width: | Height: | Size: 743 B |
4
elixir/apps/web/priv/static/images/openid-logo.svg
Normal file
4
elixir/apps/web/priv/static/images/openid-logo.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="93" height="84" viewBox="0 0 93 84" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M83.4104 32.8962C74.6607 27.4483 62.4441 24.064 49.0719 24.064C22.1624 24.064 0.370605 37.5187 0.370605 54.1102C0.370605 69.2984 18.5304 81.7626 42.0556 83.9088V75.159C26.2071 73.178 14.3206 64.5108 14.3206 54.1102C14.3206 42.3063 29.839 32.6486 49.0719 32.6486C58.6471 32.6486 67.3142 35.0424 73.5876 38.922L64.6728 44.4525H92.4903V27.2832L83.4104 32.8962Z" fill="#CCCCCC"/>
|
||||
<path d="M42.0557 9.20591V75.159V83.9087L56.0057 75.159V0.208557L42.0557 9.20591Z" fill="#FF6200"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 588 B |
@@ -13,10 +13,10 @@ defmodule Web.Acceptance.Auth.OpenIDConnectTest do
|
||||
|
||||
session
|
||||
|> visit(~p"/#{account}")
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> click(Query.link("Sign in with Vault"))
|
||||
|> Vault.userpass_flow(oidc_login, oidc_password)
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> assert_path(~p"/#{account.id}")
|
||||
|> assert_el(Query.text("You may not authenticate to this account."))
|
||||
end
|
||||
@@ -41,7 +41,7 @@ defmodule Web.Acceptance.Auth.OpenIDConnectTest do
|
||||
|
||||
session
|
||||
|> visit(~p"/#{account}")
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> click(Query.link("Sign in with Vault"))
|
||||
|> Vault.userpass_flow(oidc_login, oidc_password)
|
||||
|> assert_el(Query.css("#user-menu-button"))
|
||||
@@ -69,7 +69,7 @@ defmodule Web.Acceptance.Auth.OpenIDConnectTest do
|
||||
|
||||
session
|
||||
|> visit(~p"/#{account}")
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> click(Query.link("Sign in with Vault"))
|
||||
|> Vault.userpass_flow(oidc_login, oidc_password)
|
||||
|> assert_el(Query.css("#user-menu-button"))
|
||||
@@ -110,7 +110,7 @@ defmodule Web.Acceptance.Auth.OpenIDConnectTest do
|
||||
|
||||
session
|
||||
|> visit(~p"/#{account}?#{redirect_params}")
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> click(Query.link("Sign in with Vault"))
|
||||
|> Vault.userpass_flow(oidc_login, oidc_password)
|
||||
|> assert_el(Query.text("Client redirected"))
|
||||
@@ -175,7 +175,7 @@ defmodule Web.Acceptance.Auth.OpenIDConnectTest do
|
||||
# Sign In as an portal user
|
||||
session
|
||||
|> visit(~p"/#{account}")
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> click(Query.link("Sign in with Vault"))
|
||||
|> Vault.userpass_flow(oidc_login, oidc_password)
|
||||
|> assert_el(Query.css("#user-menu-button"))
|
||||
@@ -185,7 +185,7 @@ defmodule Web.Acceptance.Auth.OpenIDConnectTest do
|
||||
# And then to a client
|
||||
session
|
||||
|> visit(~p"/#{account}?#{redirect_params}")
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> click(Query.link("Sign in with Vault"))
|
||||
|> assert_el(Query.text("Client redirected"))
|
||||
|> assert_path(~p"/handle_client_sign_in_callback")
|
||||
@@ -237,7 +237,7 @@ defmodule Web.Acceptance.Auth.OpenIDConnectTest do
|
||||
# And then to a client
|
||||
session
|
||||
|> visit(~p"/#{account}?#{redirect_params}")
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> click(Query.link("Sign in with Vault"))
|
||||
|> Vault.userpass_flow(oidc_login, oidc_password)
|
||||
|> assert_el(Query.text("Client redirected"))
|
||||
@@ -246,7 +246,7 @@ defmodule Web.Acceptance.Auth.OpenIDConnectTest do
|
||||
# Sign In as an portal user
|
||||
session
|
||||
|> visit(~p"/#{account}")
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> click(Query.link("Sign in with Vault"))
|
||||
|> assert_el(Query.css("#user-menu-button"))
|
||||
|> Auth.assert_authenticated(identity)
|
||||
|
||||
@@ -247,7 +247,7 @@ defmodule Web.Acceptance.Auth.UserPassTest do
|
||||
defp password_login_flow(session, account, username, password, redirect_params \\ %{}) do
|
||||
session
|
||||
|> visit(~p"/#{account}?#{redirect_params}")
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in with username and password"))
|
||||
|> fill_form(%{
|
||||
"userpass[provider_identifier]" => username,
|
||||
|
||||
@@ -14,7 +14,7 @@ defmodule Web.Acceptance.AuthTest do
|
||||
|
||||
session
|
||||
|> visit(~p"/#{account}")
|
||||
|> assert_el(Query.text("Sign into #{account.name}"))
|
||||
|> assert_el(Query.text("Sign in to #{account.name}"))
|
||||
|> assert_el(Query.link("Sign in with #{openid_connect_provider.name}"))
|
||||
|> assert_el(Query.text("Sign in with username and password"))
|
||||
|> assert_el(Query.text("Sign in with email"))
|
||||
|
||||
Reference in New Issue
Block a user