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:
Jamil
2024-02-05 13:45:00 -08:00
committed by GitHub
parent 8a31a532b6
commit fcbf6a68bc
14 changed files with 93 additions and 43 deletions

View File

@@ -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

View File

@@ -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() ++
[

View File

@@ -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

View File

@@ -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 %>

View File

@@ -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>

View File

@@ -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

View File

@@ -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"

View File

@@ -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">

View 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

View 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

View 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

View File

@@ -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)

View File

@@ -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,

View File

@@ -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"))