mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
UX cleanup pt 3 (#2789)
Closes https://github.com/firezone/firezone/issues/2601 Also addresses a lot of TODOs from https://github.com/firezone/firezone/issues/2788 <img width="1728" alt="Screenshot 2023-12-01 at 18 25 11" src="https://github.com/firezone/firezone/assets/1877644/95137fca-15ab-4b8c-9598-16d92a7951c7"> <img width="1728" alt="Screenshot 2023-12-01 at 18 25 16" src="https://github.com/firezone/firezone/assets/1877644/9315b754-c3de-4336-8b59-c1d87ac83f69"> <img width="1728" alt="Screenshot 2023-12-01 at 18 25 33" src="https://github.com/firezone/firezone/assets/1877644/65245194-c922-401e-bbc4-ff4a378520d2"> <img width="1728" alt="Screenshot 2023-12-01 at 18 25 39" src="https://github.com/firezone/firezone/assets/1877644/3ac8c2c8-c0a8-4074-9cb1-123bc2c21e71"> <img width="1728" alt="Screenshot 2023-12-01 at 18 25 59" src="https://github.com/firezone/firezone/assets/1877644/7a96cf74-3a9a-4215-9b22-871dee335b30">
This commit is contained in:
@@ -35,7 +35,8 @@ defmodule Domain.Auth do
|
||||
true <- Validator.valid_uuid?(id) do
|
||||
{preload, _opts} = Keyword.pop(opts, :preload, [])
|
||||
|
||||
Provider.Query.by_id(id)
|
||||
Provider.Query.all()
|
||||
|> Provider.Query.by_id(id)
|
||||
|> Authorizer.for_subject(Provider, subject)
|
||||
|> Repo.fetch()
|
||||
|> case do
|
||||
|
||||
@@ -33,7 +33,7 @@ defmodule Domain.Auth.Adapters.OpenIDConnect do
|
||||
def identity_changeset(%Provider{} = _provider, %Ecto.Changeset{} = changeset) do
|
||||
changeset
|
||||
|> Domain.Validator.trim_change(:provider_identifier)
|
||||
|> Ecto.Changeset.put_change(:provider_state, %{})
|
||||
|> Domain.Validator.copy_change(:provider_virtual_state, :provider_state)
|
||||
|> Ecto.Changeset.put_change(:provider_virtual_state, %{})
|
||||
end
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ defmodule Domain.Auth.Provider.Changeset do
|
||||
def enable_provider(%Provider{} = provider) do
|
||||
provider
|
||||
|> change()
|
||||
|> put_default_value(:disabled_at, nil)
|
||||
|> put_change(:disabled_at, nil)
|
||||
end
|
||||
|
||||
def delete_provider(%Provider{} = provider) do
|
||||
|
||||
@@ -70,6 +70,22 @@ defmodule Domain.Policies do
|
||||
end
|
||||
end
|
||||
|
||||
def disable_policy(%Policy{} = policy, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do
|
||||
Policy.Query.by_id(policy.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.fetch_and_update(with: &Policy.Changeset.disable(&1, subject))
|
||||
end
|
||||
end
|
||||
|
||||
def enable_policy(%Policy{} = policy, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do
|
||||
Policy.Query.by_id(policy.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.fetch_and_update(with: &Policy.Changeset.enable/1)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_policy(%Policy{} = policy, %Auth.Subject{} = subject) do
|
||||
required_permissions =
|
||||
{:one_of, [Authorizer.manage_policies_permission()]}
|
||||
|
||||
@@ -11,6 +11,7 @@ defmodule Domain.Policies.Policy do
|
||||
field :created_by, Ecto.Enum, values: ~w[identity]a
|
||||
belongs_to :created_by_identity, Domain.Auth.Identity
|
||||
|
||||
field :disabled_at, :utc_datetime_usec
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -24,6 +24,18 @@ defmodule Domain.Policies.Policy.Changeset do
|
||||
|> changeset()
|
||||
end
|
||||
|
||||
def disable(%Policy{} = policy, %Auth.Subject{}) do
|
||||
policy
|
||||
|> change()
|
||||
|> put_default_value(:disabled_at, DateTime.utc_now())
|
||||
end
|
||||
|
||||
def enable(%Policy{} = policy) do
|
||||
policy
|
||||
|> change()
|
||||
|> put_change(:disabled_at, nil)
|
||||
end
|
||||
|
||||
def delete(%Policy{} = policy) do
|
||||
policy
|
||||
|> change()
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
defmodule Domain.Repo.Migrations.AddPoliciesDisabledFields do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:policies) do
|
||||
add(:disabled_at, :utc_datetime_usec)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -22,8 +22,17 @@ defmodule Domain.Auth.Adapters.GoogleWorkspaceTest do
|
||||
end
|
||||
|
||||
test "puts default provider state", %{provider: provider, changeset: changeset} do
|
||||
changeset =
|
||||
Ecto.Changeset.put_change(changeset, :provider_virtual_state, %{
|
||||
"userinfo" => %{"email" => "foo@example.com"}
|
||||
})
|
||||
|
||||
assert %Ecto.Changeset{} = changeset = identity_changeset(provider, changeset)
|
||||
assert changeset.changes == %{provider_virtual_state: %{}}
|
||||
|
||||
assert changeset.changes == %{
|
||||
provider_virtual_state: %{},
|
||||
provider_state: %{"userinfo" => %{"email" => "foo@example.com"}}
|
||||
}
|
||||
end
|
||||
|
||||
test "trims provider identifier", %{provider: provider, changeset: changeset} do
|
||||
|
||||
@@ -22,8 +22,17 @@ defmodule Domain.Auth.Adapters.OpenIDConnectTest do
|
||||
end
|
||||
|
||||
test "puts default provider state", %{provider: provider, changeset: changeset} do
|
||||
changeset =
|
||||
Ecto.Changeset.put_change(changeset, :provider_virtual_state, %{
|
||||
"userinfo" => %{"email" => "foo@example.com"}
|
||||
})
|
||||
|
||||
assert %Ecto.Changeset{} = changeset = identity_changeset(provider, changeset)
|
||||
assert changeset.changes == %{provider_state: %{}, provider_virtual_state: %{}}
|
||||
|
||||
assert changeset.changes == %{
|
||||
provider_virtual_state: %{},
|
||||
provider_state: %{"userinfo" => %{"email" => "foo@example.com"}}
|
||||
}
|
||||
end
|
||||
|
||||
test "trims provider identifier", %{provider: provider, changeset: changeset} do
|
||||
|
||||
@@ -75,11 +75,12 @@ defmodule Domain.AuthTest do
|
||||
assert fetch_provider_by_id("foo", subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns error when provider is deleted", %{account: account, subject: subject} do
|
||||
test "returns deleted provider", %{account: account, subject: subject} do
|
||||
provider = Fixtures.Auth.create_userpass_provider(account: account)
|
||||
{:ok, _provider} = delete_provider(provider, subject)
|
||||
|
||||
assert fetch_provider_by_id(provider.id, subject) == {:error, :not_found}
|
||||
assert {:ok, fetched_provider} = fetch_provider_by_id(provider.id, subject)
|
||||
assert fetched_provider.id == provider.id
|
||||
end
|
||||
|
||||
test "returns provider", %{account: account, subject: subject} do
|
||||
@@ -877,11 +878,12 @@ defmodule Domain.AuthTest do
|
||||
subject: subject,
|
||||
provider: provider
|
||||
} do
|
||||
assert {:ok, provider} = enable_provider(provider, subject)
|
||||
assert provider.disabled_at
|
||||
assert {:ok, provider} = enable_provider(provider, subject)
|
||||
assert is_nil(provider.disabled_at)
|
||||
|
||||
assert provider = Repo.get(Auth.Provider, provider.id)
|
||||
assert provider.disabled_at
|
||||
assert is_nil(provider.disabled_at)
|
||||
end
|
||||
|
||||
test "does not do anything when an provider is enabled twice", %{
|
||||
|
||||
@@ -341,6 +341,117 @@ defmodule Domain.PoliciesTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "disable_policy/2" do
|
||||
setup context do
|
||||
policy =
|
||||
Fixtures.Policies.create_policy(
|
||||
account: context.account,
|
||||
subject: context.subject
|
||||
)
|
||||
|
||||
Map.put(context, :policy, policy)
|
||||
end
|
||||
|
||||
test "disables a given policy", %{
|
||||
account: account,
|
||||
subject: subject,
|
||||
policy: policy
|
||||
} do
|
||||
other_policy = Fixtures.Policies.create_policy(account: account)
|
||||
|
||||
assert {:ok, policy} = disable_policy(policy, subject)
|
||||
assert policy.disabled_at
|
||||
|
||||
assert policy = Repo.get(Policies.Policy, policy.id)
|
||||
assert policy.disabled_at
|
||||
|
||||
assert other_policy = Repo.get(Policies.Policy, other_policy.id)
|
||||
assert is_nil(other_policy.disabled_at)
|
||||
end
|
||||
|
||||
test "does not do anything when an policy is disabled twice", %{
|
||||
subject: subject,
|
||||
account: account
|
||||
} do
|
||||
policy = Fixtures.Policies.create_policy(account: account)
|
||||
assert {:ok, _policy} = disable_policy(policy, subject)
|
||||
assert {:ok, policy} = disable_policy(policy, subject)
|
||||
assert {:ok, _policy} = disable_policy(policy, subject)
|
||||
end
|
||||
|
||||
test "does not allow to disable policies in other accounts", %{
|
||||
subject: subject
|
||||
} do
|
||||
policy = Fixtures.Policies.create_policy()
|
||||
assert disable_policy(policy, subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns error when subject can not disable policies", %{
|
||||
subject: subject,
|
||||
policy: policy
|
||||
} do
|
||||
subject = Fixtures.Auth.remove_permissions(subject)
|
||||
|
||||
assert disable_policy(policy, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
[missing_permissions: [Policies.Authorizer.manage_policies_permission()]]}}
|
||||
end
|
||||
end
|
||||
|
||||
describe "enable_policy/2" do
|
||||
setup context do
|
||||
policy =
|
||||
Fixtures.Policies.create_policy(
|
||||
account: context.account,
|
||||
subject: context.subject
|
||||
)
|
||||
|
||||
{:ok, policy} = disable_policy(policy, context.subject)
|
||||
|
||||
Map.put(context, :policy, policy)
|
||||
end
|
||||
|
||||
test "enables a given policy", %{
|
||||
subject: subject,
|
||||
policy: policy
|
||||
} do
|
||||
assert {:ok, policy} = enable_policy(policy, subject)
|
||||
assert is_nil(policy.disabled_at)
|
||||
|
||||
assert policy = Repo.get(Policies.Policy, policy.id)
|
||||
assert is_nil(policy.disabled_at)
|
||||
end
|
||||
|
||||
test "does not do anything when an policy is enabled twice", %{
|
||||
subject: subject,
|
||||
policy: policy
|
||||
} do
|
||||
assert {:ok, _policy} = enable_policy(policy, subject)
|
||||
assert {:ok, policy} = enable_policy(policy, subject)
|
||||
assert {:ok, _policy} = enable_policy(policy, subject)
|
||||
end
|
||||
|
||||
test "does not allow to enable policies in other accounts", %{
|
||||
subject: subject
|
||||
} do
|
||||
policy = Fixtures.Policies.create_policy()
|
||||
assert enable_policy(policy, subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns error when subject can not enable policies", %{
|
||||
subject: subject,
|
||||
policy: policy
|
||||
} do
|
||||
subject = Fixtures.Auth.remove_permissions(subject)
|
||||
|
||||
assert enable_policy(policy, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
[missing_permissions: [Policies.Authorizer.manage_policies_permission()]]}}
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete_policy/2" do
|
||||
setup context do
|
||||
policy =
|
||||
|
||||
@@ -15,6 +15,18 @@ Hooks.Tabs = {
|
||||
}
|
||||
}
|
||||
|
||||
Hooks.Refocus = {
|
||||
mounted() {
|
||||
this.el.addEventListener("click", (ev) => {
|
||||
ev.preventDefault();
|
||||
let target_id = ev.currentTarget.getAttribute("data-refocus");
|
||||
let el = document.getElementById(target_id);
|
||||
if (document.activeElement === el) return;
|
||||
el.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Hooks.Copy = {
|
||||
mounted() {
|
||||
this.el.addEventListener("click", (ev) => {
|
||||
@@ -31,14 +43,14 @@ Hooks.Copy = {
|
||||
icon_cl.add("hero-clipboard-document-check");
|
||||
icon_cl.add("text-green-500");
|
||||
icon_cl.remove("hero-clipboard-document");
|
||||
content.innerHTML = "Copied"
|
||||
if (content) { content.innerHTML = "Copied" }
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
icon_cl.remove("hero-clipboard-document-check");
|
||||
icon_cl.remove("text-green-500");
|
||||
icon_cl.add("hero-clipboard-document");
|
||||
content.innerHTML = "Copy"
|
||||
if (content) { content.innerHTML = "Copy" }
|
||||
}, 2000);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@fontsource/source-sans-pro": "^5.0.8",
|
||||
"flowbite": "^2.1.1"
|
||||
"flowbite": "^2.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
8
elixir/apps/web/assets/pnpm-lock.yaml
generated
8
elixir/apps/web/assets/pnpm-lock.yaml
generated
@@ -9,8 +9,8 @@ dependencies:
|
||||
specifier: ^5.0.8
|
||||
version: 5.0.8
|
||||
flowbite:
|
||||
specifier: ^2.1.1
|
||||
version: 2.1.1
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0
|
||||
|
||||
packages:
|
||||
|
||||
@@ -22,8 +22,8 @@ packages:
|
||||
resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==}
|
||||
dev: false
|
||||
|
||||
/flowbite@2.1.1:
|
||||
resolution: {integrity: sha512-FkTwNXlfWRXUhSsiE9D4bEqLN8ywdunW2qOz1z7gN+Co7h9EQIJf/Fr4xgq1NJPFa+6MeMf08QLzviU7LqB/rQ==}
|
||||
/flowbite@2.2.0:
|
||||
resolution: {integrity: sha512-Eq0qWz4a5nlxaGuUcspzpu+8Ny0A7lKEJEKcuPpkdSoF8tWjbKeuVVgKk8/q10ZE9bhXh1GHBXdCsRxu0LZTNQ==}
|
||||
dependencies:
|
||||
'@popperjs/core': 2.11.8
|
||||
mini-svg-data-uri: 1.4.4
|
||||
|
||||
@@ -70,6 +70,8 @@ defmodule Web.Auth do
|
||||
client_auth_token: client_token,
|
||||
client_csrf_token: client_csrf_token,
|
||||
actor_name: subject.actor.name,
|
||||
account_slug: subject.account.slug,
|
||||
account_name: subject.account.name,
|
||||
identity_provider_identifier: subject.identity.provider_identifier
|
||||
}
|
||||
|> Enum.reject(&is_nil(elem(&1, 1)))
|
||||
|
||||
@@ -90,6 +90,31 @@ defmodule Web.CoreComponents do
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Render an inlined copy-paste button to the right of the content block.
|
||||
|
||||
## Examples
|
||||
|
||||
<.copy id="foo">
|
||||
The lazy brown fox jumped over the quick dog.
|
||||
</.copy>
|
||||
"""
|
||||
attr :id, :string, required: true
|
||||
attr :class, :string, default: ""
|
||||
slot :inner_block, required: true
|
||||
attr :rest, :global
|
||||
|
||||
def copy(assigns) do
|
||||
~H"""
|
||||
<div id={@id} phx-hook="Copy" class={@class} {@rest}>
|
||||
<code data-copy phx-no-format><%= render_slot(@inner_block) %></code>
|
||||
<span class={~w[text-gray-400 cursor-pointer rounded]}>
|
||||
<.icon name="hero-clipboard-document" data-icon class="h-4 w-4" />
|
||||
</span>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
@doc """
|
||||
Render a tabs toggle container and its content.
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ defmodule Web.FormComponents do
|
||||
attr :id, :any, default: nil
|
||||
attr :name, :any
|
||||
attr :label, :string, default: nil
|
||||
attr :prefix, :string, default: nil
|
||||
attr :value, :any
|
||||
|
||||
attr :value_id, :any,
|
||||
@@ -204,7 +205,51 @@ defmodule Web.FormComponents do
|
||||
"""
|
||||
end
|
||||
|
||||
# All other inputs text, datetime-local, url, password, etc. are handled here...
|
||||
def input(%{type: "text", prefix: prefix} = assigns) when not is_nil(prefix) do
|
||||
~H"""
|
||||
<div phx-feedback-for={@name}>
|
||||
<.label :if={not is_nil(@label)} for={@id}><%= @label %></.label>
|
||||
<div class={[
|
||||
"flex items-center",
|
||||
"text-sm text-gray-900 bg-gray-50",
|
||||
"border-gray-300 border rounded",
|
||||
"w-full",
|
||||
"phx-no-feedback:border-gray-300",
|
||||
"focus-within:outline-none focus-within:border-blue-600",
|
||||
"peer-disabled:bg-slate-50 peer-disabled:text-slate-500 peer-disabled:border-slate-200 peer-disabled:shadow-none",
|
||||
@errors != [] && "border-rose-400"
|
||||
]}>
|
||||
<div
|
||||
class={[
|
||||
"-mr-5",
|
||||
"select-none cursor-text",
|
||||
"text-gray-500",
|
||||
"p-2.5 block"
|
||||
]}
|
||||
id={"#{@id}-prefix"}
|
||||
phx-hook="Refocus"
|
||||
data-refocus={@id}
|
||||
>
|
||||
<%= @prefix %>
|
||||
</div>
|
||||
<input
|
||||
type={@type}
|
||||
name={@name}
|
||||
id={@id}
|
||||
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
|
||||
class={[
|
||||
"text-sm text-gray-900 bg-transparent border-0",
|
||||
"p-2.5 block w-full",
|
||||
"focus:outline-none focus:border-0 focus:ring-0"
|
||||
]}
|
||||
{@rest}
|
||||
/>
|
||||
</div>
|
||||
<.error :for={msg <- @errors} data-validation-error-for={@name}><%= msg %></.error>
|
||||
</div>
|
||||
"""
|
||||
end
|
||||
|
||||
def input(assigns) do
|
||||
~H"""
|
||||
<div phx-feedback-for={@name}>
|
||||
|
||||
@@ -38,7 +38,7 @@ defmodule Web.PageComponents do
|
||||
|
||||
slot :action, required: false, doc: "A slot for action to the right of the title"
|
||||
|
||||
slot :content, required: true, doc: "A slot for content of the section" do
|
||||
slot :content, required: false, doc: "A slot for content of the section" do
|
||||
attr :flash, :any, doc: "The flash to be displayed above the content"
|
||||
end
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ defmodule Web.HomeController do
|
||||
use Web, :controller
|
||||
alias Domain.Accounts
|
||||
|
||||
def home(conn, _params) do
|
||||
def home(conn, params) do
|
||||
{accounts, conn} =
|
||||
with {:ok, recent_account_ids, conn} <- Web.Auth.list_recent_account_ids(conn),
|
||||
{:ok, accounts} <- Accounts.list_accounts_by_ids(recent_account_ids) do
|
||||
@@ -16,12 +16,22 @@ defmodule Web.HomeController do
|
||||
_other -> {[], conn}
|
||||
end
|
||||
|
||||
redirect_params =
|
||||
take_non_empty_params(params, ["client_platform", "client_csrf_token"])
|
||||
|
||||
conn
|
||||
|> put_layout(html: {Web.Layouts, :public})
|
||||
|> render("home.html", accounts: accounts)
|
||||
|> render("home.html", accounts: accounts, redirect_params: redirect_params)
|
||||
end
|
||||
|
||||
def redirect_to_sign_in(conn, %{"account_id_or_slug" => account_id_or_slug}) do
|
||||
redirect(conn, to: ~p"/#{account_id_or_slug}")
|
||||
def redirect_to_sign_in(conn, %{"account_id_or_slug" => account_id_or_slug} = params) do
|
||||
redirect_params =
|
||||
take_non_empty_params(params, ["client_platform", "client_csrf_token"])
|
||||
|
||||
redirect(conn, to: ~p"/#{account_id_or_slug}?#{redirect_params}")
|
||||
end
|
||||
|
||||
defp take_non_empty_params(map, keys) do
|
||||
map |> Map.take(keys) |> Map.reject(fn {_key, value} -> value in ["", nil] end)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -21,25 +21,39 @@ defmodule Web.HomeHTML do
|
||||
</h3>
|
||||
|
||||
<div :if={@accounts != []} class="space-y-3 items-center">
|
||||
<.account_button :for={account <- @accounts} account={account} />
|
||||
<.account_button
|
||||
:for={account <- @accounts}
|
||||
account={account}
|
||||
redirect_params={@redirect_params}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<.separator :if={@accounts != []} />
|
||||
|
||||
<.form :let={f} for={%{}} action={~p"/"} class="space-y-4 lg:space-y-6">
|
||||
<.form
|
||||
:let={f}
|
||||
for={%{}}
|
||||
action={~p"/?#{@redirect_params}"}
|
||||
class="space-y-4 lg:space-y-6"
|
||||
>
|
||||
<.input
|
||||
field={f[:account_id_or_slug]}
|
||||
type="text"
|
||||
label="Account ID or Slug"
|
||||
placeholder={~s|As shown in your "Welcome to Firezone" email|}
|
||||
prefix={url(~p"/")}
|
||||
required
|
||||
autofocus
|
||||
/>
|
||||
<p>As shown in your "Welcome to Firezone" email</p>
|
||||
|
||||
<.button class="w-full">
|
||||
Go to Sign In page
|
||||
</.button>
|
||||
</.form>
|
||||
<p :if={Domain.Config.sign_up_enabled?()} class="py-2">
|
||||
<p
|
||||
:if={Domain.Config.sign_up_enabled?() and is_nil(@redirect_params["client_platform"])}
|
||||
class="py-2"
|
||||
>
|
||||
Don't have an account?
|
||||
<a href={~p"/sign_up"} class="font-medium text-blue-600 hover:text-blue-500">
|
||||
Sign up here.
|
||||
@@ -54,7 +68,7 @@ defmodule Web.HomeHTML do
|
||||
|
||||
def account_button(assigns) do
|
||||
~H"""
|
||||
<a href={~p"/#{@account}"} class={~w[
|
||||
<a href={~p"/#{@account}?#{@redirect_params}"} class={~w[
|
||||
w-full inline-flex items-center justify-center py-2.5 px-5
|
||||
bg-white rounded
|
||||
text-sm font-medium text-gray-900
|
||||
|
||||
@@ -12,6 +12,8 @@ defmodule Web.Clients.Index do
|
||||
end
|
||||
end
|
||||
|
||||
# subscribe for presence
|
||||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<.breadcrumbs account={@account}>
|
||||
|
||||
@@ -42,6 +42,17 @@ defmodule Web.Policies.Index do
|
||||
<%= policy.resource.name %>
|
||||
</.link>
|
||||
</:col>
|
||||
<:col :let={policy} label="STATUS">
|
||||
<%= if is_nil(policy.deleted_at) do %>
|
||||
<%= if is_nil(policy.disabled_at) do %>
|
||||
Active
|
||||
<% else %>
|
||||
Disabled
|
||||
<% end %>
|
||||
<% else %>
|
||||
Deleted
|
||||
<% end %>
|
||||
</:col>
|
||||
<:empty>
|
||||
<div class="flex justify-center text-center text-slate-500 p-4">
|
||||
<div class="w-auto">
|
||||
|
||||
@@ -38,6 +38,7 @@ defmodule Web.Policies.Show do
|
||||
<.section>
|
||||
<:title>
|
||||
<%= @page_title %>: <code><%= @policy.id %></code>
|
||||
<span :if={not is_nil(@policy.disabled_at)} class="text-orange-600">(disabled)</span>
|
||||
<span :if={not is_nil(@policy.deleted_at)} class="text-red-600">(deleted)</span>
|
||||
</:title>
|
||||
<:action :if={is_nil(@policy.deleted_at)}>
|
||||
@@ -45,6 +46,22 @@ defmodule Web.Policies.Show do
|
||||
Edit Policy
|
||||
</.edit_button>
|
||||
</:action>
|
||||
<:action :if={is_nil(@policy.deleted_at)}>
|
||||
<.button
|
||||
:if={not is_nil(@policy.disabled_at)}
|
||||
phx-click="enable"
|
||||
data-confirm="Are you sure want to enable this policy?"
|
||||
>
|
||||
Enable Policy
|
||||
</.button>
|
||||
<.button
|
||||
:if={is_nil(@policy.disabled_at)}
|
||||
phx-click="disable"
|
||||
data-confirm="Are you sure want to disable this policy? All authorizations will be revoked and users can loose access to the resource."
|
||||
>
|
||||
Disable Policy
|
||||
</.button>
|
||||
</:action>
|
||||
<:content>
|
||||
<.vertical_table id="policy">
|
||||
<.vertical_table_row>
|
||||
@@ -157,12 +174,37 @@ defmodule Web.Policies.Show do
|
||||
Delete Policy
|
||||
</.delete_button>
|
||||
</:action>
|
||||
<:content></:content>
|
||||
</.danger_zone>
|
||||
"""
|
||||
end
|
||||
|
||||
def handle_event("delete", %{"id" => _policy_id}, socket) do
|
||||
def handle_event("disable", _params, socket) do
|
||||
{:ok, policy} = Policies.disable_policy(socket.assigns.policy, socket.assigns.subject)
|
||||
|
||||
policy = %{
|
||||
policy
|
||||
| actor_group: socket.assigns.policy.actor_group,
|
||||
resource: socket.assigns.policy.resource,
|
||||
created_by_identity: socket.assigns.policy.created_by_identity
|
||||
}
|
||||
|
||||
{:noreply, assign(socket, policy: policy)}
|
||||
end
|
||||
|
||||
def handle_event("enable", _params, socket) do
|
||||
{:ok, policy} = Policies.enable_policy(socket.assigns.policy, socket.assigns.subject)
|
||||
|
||||
policy = %{
|
||||
policy
|
||||
| actor_group: socket.assigns.policy.actor_group,
|
||||
resource: socket.assigns.policy.resource,
|
||||
created_by_identity: socket.assigns.policy.created_by_identity
|
||||
}
|
||||
|
||||
{:noreply, assign(socket, policy: policy)}
|
||||
end
|
||||
|
||||
def handle_event("delete", _params, socket) do
|
||||
{:ok, _} = Policies.delete_policy(socket.assigns.policy, socket.assigns.subject)
|
||||
{:noreply, push_navigate(socket, to: ~p"/#{socket.assigns.account}/policies")}
|
||||
end
|
||||
|
||||
@@ -24,7 +24,9 @@ defmodule Web.Settings.Account do
|
||||
</.vertical_table_row>
|
||||
<.vertical_table_row>
|
||||
<:label>Account Slug</:label>
|
||||
<:value><%= @account.slug %></:value>
|
||||
<:value>
|
||||
<.copy id="account-slug"><%= @account.slug %></.copy>
|
||||
</:value>
|
||||
</.vertical_table_row>
|
||||
</.vertical_table>
|
||||
</div>
|
||||
|
||||
@@ -29,29 +29,35 @@ defmodule Web.Settings.IdentityProviders.GoogleWorkspace.Show do
|
||||
<.section>
|
||||
<:title>
|
||||
Identity Provider <code><%= @provider.name %></code>
|
||||
<span :if={not is_nil(@provider.disabled_at)} class="text-orange-600">(disabled)</span>
|
||||
<span :if={not is_nil(@provider.deleted_at)} class="text-red-600">(deleted)</span>
|
||||
</:title>
|
||||
<:action>
|
||||
<:action :if={is_nil(@provider.deleted_at)}>
|
||||
<.edit_button navigate={
|
||||
~p"/#{@account}/settings/identity_providers/google_workspace/#{@provider.id}/edit"
|
||||
}>
|
||||
Edit
|
||||
</.edit_button>
|
||||
</:action>
|
||||
<:action>
|
||||
<:action :if={is_nil(@provider.deleted_at)}>
|
||||
<%= if @provider.adapter_state["status"] != "pending_access_token" do %>
|
||||
<.button :if={not is_nil(@provider.disabled_at)} phx-click="enable">
|
||||
<.button
|
||||
:if={not is_nil(@provider.disabled_at)}
|
||||
phx-click="enable"
|
||||
data-confirm="Are you sure want to enable this provider?"
|
||||
>
|
||||
Enable Identity Provider
|
||||
</.button>
|
||||
<.button
|
||||
:if={is_nil(@provider.disabled_at)}
|
||||
phx-click="disable"
|
||||
data-confirm="Are you sure want to disable this provider?"
|
||||
data-confirm="Are you sure want to disable this provider? All authorizations will be revoked and actors won't be able to use it to access Firezone."
|
||||
>
|
||||
Disable Identity Provider
|
||||
</.button>
|
||||
<% end %>
|
||||
</:action>
|
||||
<:action>
|
||||
<:action :if={is_nil(@provider.deleted_at)}>
|
||||
<.button
|
||||
style="primary"
|
||||
navigate={
|
||||
@@ -96,7 +102,7 @@ defmodule Web.Settings.IdentityProviders.GoogleWorkspace.Show do
|
||||
</:content>
|
||||
</.section>
|
||||
|
||||
<.danger_zone>
|
||||
<.danger_zone :if={is_nil(@provider.deleted_at)}>
|
||||
<:action>
|
||||
<.delete_button
|
||||
data-confirm="Are you sure want to delete this provider along with all related data?"
|
||||
|
||||
@@ -28,8 +28,10 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Show do
|
||||
<.section>
|
||||
<:title>
|
||||
Identity Provider <code><%= @provider.name %></code>
|
||||
<span :if={not is_nil(@provider.disabled_at)} class="text-orange-600">(disabled)</span>
|
||||
<span :if={not is_nil(@provider.deleted_at)} class="text-red-600">(deleted)</span>
|
||||
</:title>
|
||||
<:action>
|
||||
<:action :if={is_nil(@provider.deleted_at)}>
|
||||
<.edit_button navigate={
|
||||
~p"/#{@account}/settings/identity_providers/openid_connect/#{@provider}/edit"
|
||||
}>
|
||||
@@ -37,21 +39,25 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Show do
|
||||
</.edit_button>
|
||||
</:action>
|
||||
<!-- Wondering if these next two buttons can be combined? -->
|
||||
<:action>
|
||||
<.button :if={not is_nil(@provider.disabled_at)} phx-click="enable">
|
||||
<:action :if={is_nil(@provider.deleted_at)}>
|
||||
<.button
|
||||
:if={not is_nil(@provider.disabled_at)}
|
||||
phx-click="enable"
|
||||
data-confirm="Are you sure want to enable this provider?"
|
||||
>
|
||||
Enable
|
||||
</.button>
|
||||
</:action>
|
||||
<:action>
|
||||
<:action :if={is_nil(@provider.deleted_at)}>
|
||||
<.button
|
||||
:if={is_nil(@provider.disabled_at)}
|
||||
phx-click="disable"
|
||||
data-confirm="Are you sure want to disable this provider?"
|
||||
data-confirm="Are you sure want to disable this provider? All authorizations will be revoked and actors won't be able to use it to access Firezone."
|
||||
>
|
||||
Disable
|
||||
</.button>
|
||||
</:action>
|
||||
<:action>
|
||||
<:action :if={is_nil(@provider.deleted_at)}>
|
||||
<.button
|
||||
style="primary"
|
||||
navigate={
|
||||
@@ -115,10 +121,7 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Show do
|
||||
</div>
|
||||
</:content>
|
||||
</.section>
|
||||
<.section>
|
||||
<:title>
|
||||
Danger zone
|
||||
</:title>
|
||||
<.danger_zone :if={is_nil(@provider.deleted_at)}>
|
||||
<:action>
|
||||
<.delete_button
|
||||
data-confirm="Are you sure want to delete this provider along with all related data?"
|
||||
@@ -127,8 +130,7 @@ defmodule Web.Settings.IdentityProviders.OpenIDConnect.Show do
|
||||
Delete Identity Provider
|
||||
</.delete_button>
|
||||
</:action>
|
||||
<:content></:content>
|
||||
</.section>
|
||||
</.danger_zone>
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
@@ -31,15 +31,21 @@ defmodule Web.Settings.IdentityProviders.System.Show do
|
||||
<.section>
|
||||
<:title>
|
||||
Identity Provider <code><%= @provider.name %></code>
|
||||
<span :if={not is_nil(@provider.disabled_at)} class="text-orange-600">(disabled)</span>
|
||||
<span :if={not is_nil(@provider.deleted_at)} class="text-red-600">(deleted)</span>
|
||||
</:title>
|
||||
<:action>
|
||||
<.button :if={not is_nil(@provider.disabled_at)} phx-click="enable">
|
||||
<:action :if={is_nil(@provider.deleted_at)}>
|
||||
<.button
|
||||
:if={not is_nil(@provider.disabled_at)}
|
||||
phx-click="enable"
|
||||
data-confirm="Are you sure want to enable this provider?"
|
||||
>
|
||||
Enable Identity Provider
|
||||
</.button>
|
||||
<.button
|
||||
:if={is_nil(@provider.disabled_at)}
|
||||
phx-click="disable"
|
||||
data-confirm="Are you sure want to disable this provider?"
|
||||
data-confirm="Are you sure want to disable this provider? All authorizations will be revoked and actors won't be able to use it to access Firezone."
|
||||
>
|
||||
Disable Identity Provider
|
||||
</.button>
|
||||
@@ -74,10 +80,7 @@ defmodule Web.Settings.IdentityProviders.System.Show do
|
||||
</:content>
|
||||
</.section>
|
||||
|
||||
<.section>
|
||||
<:title>
|
||||
Danger zone
|
||||
</:title>
|
||||
<.danger_zone :if={is_nil(@provider.deleted_at)}>
|
||||
<:action>
|
||||
<.delete_button
|
||||
data-confirm="Are you sure want to delete this provider along with all related data?"
|
||||
@@ -86,8 +89,7 @@ defmodule Web.Settings.IdentityProviders.System.Show do
|
||||
Delete Identity Provider
|
||||
</.delete_button>
|
||||
</:action>
|
||||
<:content></:content>
|
||||
</.section>
|
||||
</.danger_zone>
|
||||
"""
|
||||
end
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ defmodule Web.SignUp do
|
||||
embeds_one(:actor, Actors.Actor)
|
||||
end
|
||||
|
||||
def changeset(%Registration{} = registration, attrs) do
|
||||
registration
|
||||
def changeset(attrs) do
|
||||
%Registration{}
|
||||
|> Ecto.Changeset.cast(attrs, [:email])
|
||||
|> Ecto.Changeset.validate_required([:email])
|
||||
|> Ecto.Changeset.validate_format(:email, ~r/.+@.+/)
|
||||
@@ -35,7 +35,7 @@ defmodule Web.SignUp do
|
||||
real_ip = Web.Auth.real_ip(socket)
|
||||
|
||||
changeset =
|
||||
Registration.changeset(%Registration{}, %{
|
||||
Registration.changeset(%{
|
||||
account: %{slug: "placeholder"},
|
||||
actor: %{type: :account_admin_user}
|
||||
})
|
||||
@@ -44,9 +44,12 @@ defmodule Web.SignUp do
|
||||
assign(socket,
|
||||
form: to_form(changeset),
|
||||
account: nil,
|
||||
provider: nil,
|
||||
user_agent: user_agent,
|
||||
real_ip: real_ip,
|
||||
sign_up_enabled?: Config.sign_up_enabled?()
|
||||
sign_up_enabled?: Config.sign_up_enabled?(),
|
||||
account_name_changed?: false,
|
||||
actor_name_changed?: false
|
||||
)
|
||||
|
||||
{:ok, socket}
|
||||
@@ -76,7 +79,12 @@ defmodule Web.SignUp do
|
||||
|
||||
<:item>
|
||||
<.sign_up_form :if={@account == nil && @sign_up_enabled?} flash={@flash} form={@form} />
|
||||
<.welcome :if={@account && @sign_up_enabled?} account={@account} />
|
||||
<.welcome
|
||||
:if={@account && @sign_up_enabled?}
|
||||
account={@account}
|
||||
provider={@provider}
|
||||
identity={@identity}
|
||||
/>
|
||||
<.sign_up_disabled :if={!@sign_up_enabled?} />
|
||||
</:item>
|
||||
</.intersperse_blocks>
|
||||
@@ -101,41 +109,61 @@ defmodule Web.SignUp do
|
||||
~H"""
|
||||
<div class="space-y-6">
|
||||
<div class="text-center text-gray-900">
|
||||
Your account has been created! Please check your email for sign in instructions.
|
||||
Your account has been created!
|
||||
<p>Please check your email for sign in instructions.</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="px-12">
|
||||
<table class="border-collapse table-fixed w-full text-sm">
|
||||
<table class="border-collapse w-full text-sm">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class={~w[border-b border-slate-100 p-4 pl-8 text-gray-900]}>
|
||||
<td class={~w[border-b border-slate-100 py-4 text-gray-900]}>
|
||||
Account Name:
|
||||
</td>
|
||||
<td class={~w[border-b border-slate-100 p-4 pl-8 text-gray-900]}>
|
||||
<td class={~w[border-b border-slate-100 py-4 text-gray-900]}>
|
||||
<%= @account.name %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class={~w[border-b border-slate-100 p-4 pl-8 text-gray-900]}>
|
||||
<td class={~w[border-b border-slate-100 py-4 text-gray-900]}>
|
||||
Account Slug:
|
||||
</td>
|
||||
<td class={~w[border-b border-slate-100 p-4 pl-8 text-gray-900]}>
|
||||
<td class={~w[border-b border-slate-100 py-4 text-gray-900]}>
|
||||
<%= @account.slug %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class={~w[border-b border-slate-100 py-4 text-gray-900]}>
|
||||
Sign In URL:
|
||||
</td>
|
||||
<td class={~w[border-b border-slate-100 py-4 text-gray-900]}>
|
||||
<.link class="font-medium text-blue-600 hover:underline" navigate={~p"/#{@account}"}>
|
||||
<%= url(~p"/#{@account}") %>
|
||||
</.link>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-base leading-7 text-center text-gray-900">
|
||||
<div>
|
||||
Sign In URL
|
||||
</div>
|
||||
<div>
|
||||
<.link class="font-medium text-blue-600 hover:underline" navigate={~p"/#{@account.slug}"}>
|
||||
<%= "#{Web.Endpoint.url()}/#{@account.slug}" %>
|
||||
</.link>
|
||||
</div>
|
||||
<.form
|
||||
for={%{}}
|
||||
id="resend-email"
|
||||
as={:email}
|
||||
class="inline"
|
||||
action={~p"/#{@account}/sign_in/providers/#{@provider}/request_magic_link"}
|
||||
method="post"
|
||||
>
|
||||
<.input
|
||||
type="hidden"
|
||||
name="email[provider_identifier]"
|
||||
value={@identity.provider_identifier}
|
||||
/>
|
||||
<.submit_button class="w-full">
|
||||
Sign In
|
||||
</.submit_button>
|
||||
</.form>
|
||||
</div>
|
||||
</div>
|
||||
"""
|
||||
@@ -147,12 +175,22 @@ defmodule Web.SignUp do
|
||||
Sign Up Now
|
||||
</h3>
|
||||
<.simple_form for={@form} class="space-y-4 lg:space-y-6" phx-submit="submit" phx-change="validate">
|
||||
<.input
|
||||
field={@form[:email]}
|
||||
type="text"
|
||||
label="Email"
|
||||
placeholder="Enter your work email here"
|
||||
required
|
||||
autofocus
|
||||
phx-debounce="300"
|
||||
/>
|
||||
|
||||
<.inputs_for :let={account} field={@form[:account]}>
|
||||
<.input
|
||||
field={account[:name]}
|
||||
type="text"
|
||||
label="Account Name"
|
||||
placeholder="Enter an Account Name here"
|
||||
placeholder="Enter an account name"
|
||||
required
|
||||
phx-debounce="300"
|
||||
/>
|
||||
@@ -171,15 +209,6 @@ defmodule Web.SignUp do
|
||||
<.input field={actor[:type]} type="hidden" />
|
||||
</.inputs_for>
|
||||
|
||||
<.input
|
||||
field={@form[:email]}
|
||||
type="text"
|
||||
label="Email"
|
||||
placeholder="Enter your email here"
|
||||
required
|
||||
phx-debounce="300"
|
||||
/>
|
||||
|
||||
<:actions>
|
||||
<.button phx-disable-with="Creating Account..." class="w-full">
|
||||
Create Account
|
||||
@@ -218,23 +247,37 @@ defmodule Web.SignUp do
|
||||
"""
|
||||
end
|
||||
|
||||
def handle_event("validate", %{"registration" => attrs}, socket) do
|
||||
def handle_event("validate", %{"registration" => attrs} = payload, socket) do
|
||||
account_name_changed? =
|
||||
socket.assigns.account_name_changed? ||
|
||||
payload["_target"] == ["registration", "account", "name"]
|
||||
|
||||
actor_name_changed? =
|
||||
socket.assigns.actor_name_changed? ||
|
||||
payload["_target"] == ["registration", "actor", "name"]
|
||||
|
||||
changeset =
|
||||
%Registration{}
|
||||
|> Registration.changeset(attrs)
|
||||
attrs
|
||||
|> maybe_put_default_account_name(account_name_changed?)
|
||||
|> maybe_put_default_actor_name(actor_name_changed?)
|
||||
|> Registration.changeset()
|
||||
|> Map.put(:action, :validate)
|
||||
|
||||
socket = assign(socket, form: to_form(changeset))
|
||||
|
||||
{:noreply, socket}
|
||||
{:noreply,
|
||||
assign(socket,
|
||||
form: to_form(changeset),
|
||||
account_name_changed?: account_name_changed?,
|
||||
actor_name_changed?: actor_name_changed?
|
||||
)}
|
||||
end
|
||||
|
||||
def handle_event("submit", %{"registration" => orig_attrs}, socket) do
|
||||
attrs = put_in(orig_attrs, ["actor", "type"], :account_admin_user)
|
||||
|
||||
def handle_event("submit", %{"registration" => attrs}, socket) do
|
||||
changeset =
|
||||
%Registration{}
|
||||
|> Registration.changeset(attrs)
|
||||
attrs
|
||||
|> maybe_put_default_account_name()
|
||||
|> maybe_put_default_actor_name()
|
||||
|> put_in(["actor", "type"], :account_admin_user)
|
||||
|> Registration.changeset()
|
||||
|> Map.put(:action, :insert)
|
||||
|
||||
if changeset.valid? && socket.assigns.sign_up_enabled? do
|
||||
@@ -279,7 +322,7 @@ defmodule Web.SignUp do
|
||||
)
|
||||
|
||||
case Domain.Repo.transaction(multi) do
|
||||
{:ok, %{account: account, identity: identity}} ->
|
||||
{:ok, %{account: account, provider: provider, identity: identity}} ->
|
||||
{:ok, _} =
|
||||
Web.Mailer.AuthEmail.sign_up_link_email(
|
||||
account,
|
||||
@@ -289,7 +332,7 @@ defmodule Web.SignUp do
|
||||
)
|
||||
|> Web.Mailer.deliver()
|
||||
|
||||
socket = assign(socket, account: account)
|
||||
socket = assign(socket, account: account, provider: provider, identity: identity)
|
||||
{:noreply, socket}
|
||||
|
||||
{:error, :account, err_changeset, _effects_so_far} ->
|
||||
@@ -302,4 +345,31 @@ defmodule Web.SignUp do
|
||||
{:noreply, assign(socket, form: to_form(changeset))}
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_put_default_account_name(attrs, account_name_changed? \\ true)
|
||||
|
||||
defp maybe_put_default_account_name(attrs, true) do
|
||||
attrs
|
||||
end
|
||||
|
||||
defp maybe_put_default_account_name(attrs, false) do
|
||||
case String.split(attrs["email"], "@", parts: 2) do
|
||||
[default_name | _] when byte_size(default_name) > 0 ->
|
||||
put_in(attrs, ["account", "name"], "#{default_name}'s account")
|
||||
|
||||
_ ->
|
||||
attrs
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_put_default_actor_name(attrs, actor_name_changed? \\ true)
|
||||
|
||||
defp maybe_put_default_actor_name(attrs, true) do
|
||||
attrs
|
||||
end
|
||||
|
||||
defp maybe_put_default_actor_name(attrs, false) do
|
||||
[default_name | _] = String.split(attrs["email"], "@", parts: 2)
|
||||
put_in(attrs, ["actor", "name"], default_name)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -80,7 +80,14 @@ defmodule Web.AuthTest do
|
||||
|
||||
redirected_to = conn |> signed_in_redirect(subject, "android", "foo") |> redirected_to()
|
||||
assert redirected_to =~ "/handle_client_auth_callback?"
|
||||
assert redirected_to =~ "client_auth_token="
|
||||
assert redirected_to =~ "client_csrf_token=foo"
|
||||
assert redirected_to =~ "actor_name=#{URI.encode_www_form(subject.actor.name)}"
|
||||
assert redirected_to =~ "account_name=#{subject.account.name}"
|
||||
assert redirected_to =~ "account_slug=#{subject.account.slug}"
|
||||
|
||||
assert redirected_to =~
|
||||
"identity_provider_identifier=#{subject.identity.provider_identifier}"
|
||||
end
|
||||
|
||||
test "redirects admin user to the post-login path if platform url is missing", %{
|
||||
|
||||
@@ -183,5 +183,36 @@ defmodule Web.Live.Policies.ShowTest do
|
||||
{:error, {:live_redirect, %{to: ~p"/#{account}/policies", kind: :push}}}
|
||||
|
||||
assert Repo.get(Domain.Policies.Policy, policy.id).deleted_at
|
||||
|
||||
{:ok, _lv, html} =
|
||||
conn
|
||||
|> authorize_conn(identity)
|
||||
|> live(~p"/#{account}/policies/#{policy}")
|
||||
|
||||
assert html =~ "(deleted)"
|
||||
end
|
||||
|
||||
test "allows disabling and enabling policy", %{
|
||||
account: account,
|
||||
policy: policy,
|
||||
identity: identity,
|
||||
conn: conn
|
||||
} do
|
||||
{:ok, lv, _html} =
|
||||
conn
|
||||
|> authorize_conn(identity)
|
||||
|> live(~p"/#{account}/policies/#{policy}")
|
||||
|
||||
assert lv
|
||||
|> element("button", "Disable Policy")
|
||||
|> render_click() =~ "(disabled)"
|
||||
|
||||
assert Repo.get(Domain.Policies.Policy, policy.id).disabled_at
|
||||
|
||||
refute lv
|
||||
|> element("button", "Enable Policy")
|
||||
|> render_click() =~ "(disabled)"
|
||||
|
||||
refute Repo.get(Domain.Policies.Policy, policy.id).disabled_at
|
||||
end
|
||||
end
|
||||
|
||||
@@ -56,6 +56,6 @@ defmodule Web.Live.Settings.Account.IndexTest do
|
||||
|
||||
assert rows["account name"] == account.name
|
||||
assert rows["account id"] == account.id
|
||||
assert rows["account slug"] == account.slug
|
||||
assert rows["account slug"] =~ account.slug
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,7 +35,7 @@ defmodule Web.Live.Settings.IdentityProviders.GoogleWorkspace.ShowTest do
|
||||
}}}
|
||||
end
|
||||
|
||||
test "renders not found error when provider is deleted", %{
|
||||
test "renders deleted provider without action buttons", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
identity: identity,
|
||||
@@ -43,11 +43,16 @@ defmodule Web.Live.Settings.IdentityProviders.GoogleWorkspace.ShowTest do
|
||||
} do
|
||||
provider = Fixtures.Auth.delete_provider(provider)
|
||||
|
||||
assert_raise Web.LiveErrors.NotFoundError, fn ->
|
||||
{:ok, _lv, html} =
|
||||
conn
|
||||
|> authorize_conn(identity)
|
||||
|> live(~p"/#{account}/settings/identity_providers/google_workspace/#{provider}")
|
||||
end
|
||||
|
||||
assert html =~ "(deleted)"
|
||||
refute html =~ "Danger Zone"
|
||||
refute html =~ "Add"
|
||||
refute html =~ "Edit"
|
||||
refute html =~ "Deploy"
|
||||
end
|
||||
|
||||
test "renders breadcrumbs item", %{
|
||||
|
||||
@@ -35,7 +35,7 @@ defmodule Web.Live.Settings.IdentityProviders.OpenIDConnect.ShowTest do
|
||||
}}}
|
||||
end
|
||||
|
||||
test "renders not found error when provider is deleted", %{
|
||||
test "renders deleted provider without action buttons", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
identity: identity,
|
||||
@@ -43,11 +43,15 @@ defmodule Web.Live.Settings.IdentityProviders.OpenIDConnect.ShowTest do
|
||||
} do
|
||||
provider = Fixtures.Auth.delete_provider(provider)
|
||||
|
||||
assert_raise Web.LiveErrors.NotFoundError, fn ->
|
||||
{:ok, _lv, html} =
|
||||
conn
|
||||
|> authorize_conn(identity)
|
||||
|> live(~p"/#{account}/settings/identity_providers/openid_connect/#{provider}")
|
||||
end
|
||||
|
||||
assert html =~ "(deleted)"
|
||||
refute html =~ "Danger Zone"
|
||||
refute html =~ "Edit"
|
||||
refute html =~ "Deploy"
|
||||
end
|
||||
|
||||
test "renders breadcrumbs item", %{
|
||||
|
||||
@@ -31,7 +31,7 @@ defmodule Web.Live.Settings.IdentityProviders.System.ShowTest do
|
||||
}}}
|
||||
end
|
||||
|
||||
test "renders not found error when provider is deleted", %{
|
||||
test "renders deleted provider without action buttons", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
identity: identity,
|
||||
@@ -39,11 +39,16 @@ defmodule Web.Live.Settings.IdentityProviders.System.ShowTest do
|
||||
} do
|
||||
provider = Fixtures.Auth.delete_provider(provider)
|
||||
|
||||
assert_raise Web.LiveErrors.NotFoundError, fn ->
|
||||
{:ok, _lv, html} =
|
||||
conn
|
||||
|> authorize_conn(identity)
|
||||
|> live(~p"/#{account}/settings/identity_providers/system/#{provider}")
|
||||
end
|
||||
|
||||
assert html =~ "(deleted)"
|
||||
refute html =~ "Danger Zone"
|
||||
refute html =~ "Add"
|
||||
refute html =~ "Edit"
|
||||
refute html =~ "Deploy"
|
||||
end
|
||||
|
||||
test "renders breadcrumbs item", %{
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"bypass": {:hex, :bypass, "2.1.0", "909782781bf8e20ee86a9cabde36b259d44af8b9f38756173e8f5e2e1fabb9b1", [:mix], [{:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:ranch, "~> 1.3", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "d9b5df8fa5b7a6efa08384e9bbecfe4ce61c77d28a4282f79e02f1ef78d96b80"},
|
||||
"castore": {:hex, :castore, "1.0.4", "ff4d0fb2e6411c0479b1d965a814ea6d00e51eb2f58697446e9c41a97d940b28", [:mix], [], "hexpm", "9418c1b8144e11656f0be99943db4caf04612e3eaecefb5dae9a2a87565584f8"},
|
||||
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
|
||||
"chatterbox": {:hex, :ts_chatterbox, "0.13.0", "6f059d97bcaa758b8ea6fffe2b3b81362bd06b639d3ea2bb088335511d691ebf", [:rebar3], [{:hpack, "~> 0.2.3", [hex: :hpack_erl, repo: "hexpm", optional: false]}], "hexpm", "b93d19104d86af0b3f2566c4cba2a57d2e06d103728246ba1ac6c3c0ff010aa7"},
|
||||
"cldr_utils": {:hex, :cldr_utils, "2.24.1", "5ff8c8c55f96666228827bcf85a23d632022def200566346545d01d15e4c30dc", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "1820300531b5b849d0bc468e5a87cd64f8f2c5191916f548cbe69b2efc203780"},
|
||||
"chatterbox": {:hex, :ts_chatterbox, "0.15.1", "5cac4d15dd7ad61fc3c4415ce4826fc563d4643dee897a558ec4ea0b1c835c9c", [:rebar3], [{:hpack, "~> 0.3.0", [hex: :hpack_erl, repo: "hexpm", optional: false]}], "hexpm", "4f75b91451338bc0da5f52f3480fa6ef6e3a2aeecfc33686d6b3d0a0948f31aa"},
|
||||
"cldr_utils": {:hex, :cldr_utils, "2.24.2", "364fa30be55d328e704629568d431eb74cd2f085752b27f8025520b566352859", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "3362b838836a9f0fa309de09a7127e36e67310e797d556db92f71b548832c7cf"},
|
||||
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
|
||||
"comeonin": {:hex, :comeonin, "5.4.0", "246a56ca3f41d404380fc6465650ddaa532c7f98be4bda1b4656b3a37cc13abe", [:mix], [], "hexpm", "796393a9e50d01999d56b7b8420ab0481a7538d0caf80919da493b4a6e51faf1"},
|
||||
"cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
|
||||
@@ -23,12 +23,12 @@
|
||||
"ecto_sql": {:hex, :ecto_sql, "3.11.0", "c787b24b224942b69c9ff7ab9107f258ecdc68326be04815c6cce2941b6fad1c", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.11.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "77aa3677169f55c2714dda7352d563002d180eb33c0dc29cd36d39c0a1a971f5"},
|
||||
"elixir_make": {:hex, :elixir_make, "0.7.7", "7128c60c2476019ed978210c245badf08b03dbec4f24d05790ef791da11aa17c", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5bc19fff950fad52bbe5f211b12db9ec82c6b34a9647da0c2224b8b8464c7e6c"},
|
||||
"erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
|
||||
"esbuild": {:hex, :esbuild, "0.7.1", "fa0947e8c3c3c2f86c9bf7e791a0a385007ccd42b86885e8e893bdb6631f5169", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "66661cdf70b1378ee4dc16573fcee67750b59761b2605a0207c267ab9d19f13c"},
|
||||
"ex_cldr": {:hex, :ex_cldr, "2.37.4", "3e2c04d9c691a75a8b7e808dfcbacedb9cdf3e73f819d1b4174f8f065e5f29c1", [:mix], [{:cldr_utils, "~> 2.21", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "2bcb5de0095324ba645b4e156bf346add156d8b928f0ffd985c61664d981ad3d"},
|
||||
"esbuild": {:hex, :esbuild, "0.8.1", "0cbf919f0eccb136d2eeef0df49c4acf55336de864e63594adcea3814f3edf41", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "25fc876a67c13cb0a776e7b5d7974851556baeda2085296c14ab48555ea7560f"},
|
||||
"ex_cldr": {:hex, :ex_cldr, "2.37.5", "9da6d97334035b961d2c2de167dc6af8cd3e09859301a5b8f49f90bd8b034593", [:mix], [{:cldr_utils, "~> 2.21", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "74ad5ddff791112ce4156382e171a5f5d3766af9d5c4675e0571f081fe136479"},
|
||||
"ex_cldr_calendars": {:hex, :ex_cldr_calendars, "1.22.1", "3e5150f1fe7698e0fa118aeedcca1b5920d0a552bc40c81cf65ca9b0a4ea4cc3", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr_lists, "~> 2.10", [hex: :ex_cldr_lists, repo: "hexpm", optional: true]}, {:ex_cldr_numbers, "~> 2.31", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:ex_cldr_units, "~> 3.16", [hex: :ex_cldr_units, repo: "hexpm", optional: true]}, {:ex_doc, "~> 0.21", [hex: :ex_doc, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "e7408cd9e8318b2ef93b76728e84484ddc3ea6d7c894fbc811c54122a7140169"},
|
||||
"ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.15.0", "aadd34e91cfac7ef6b03fe8f47f8c6fa8c5daf3f89b5d9fee64ec545ded839cf", [:mix], [{:ex_cldr, "~> 2.34", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "0521316396c66877a2d636219767560bb2397c583341fcb154ecf9f3000e6ff8"},
|
||||
"ex_cldr_dates_times": {:hex, :ex_cldr_dates_times, "2.15.0", "63a3f611aec735bc2a29be8792db32d350277aadc07f0b1c09af539b87c93d66", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr_calendars, "~> 1.22", [hex: :ex_cldr_calendars, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.31", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:tz, "~> 0.26", [hex: :tz, repo: "hexpm", optional: true]}], "hexpm", "4e61921901e8d58704f395f3e94b5ef6bcd02bc54aaf8475da3cf5297cb70369"},
|
||||
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.32.2", "5e0e3031d3f54b51fe7078a7a94592987b70b06d631bdc88813b222dc5a8b1bd", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.37", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, ">= 2.14.2", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "91257684a9c4d6abdf738f0cc5671837de876e69552e8bd4bc5fa1bfd5817713"},
|
||||
"ex_cldr_currencies": {:hex, :ex_cldr_currencies, "2.15.1", "e92ba17c41e7405b7784e0e65f406b5f17cfe313e0e70de9befd653e12854822", [:mix], [{:ex_cldr, "~> 2.34", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "31df8bd37688340f8819bdd770eb17d659652078d34db632b85d4a32864d6a25"},
|
||||
"ex_cldr_dates_times": {:hex, :ex_cldr_dates_times, "2.16.0", "d9848a5de83b6f1bcba151cc43d63b5c6311813cd605b1df1afd896dfdd21001", [:mix], [{:calendar_interval, "~> 0.2", [hex: :calendar_interval, repo: "hexpm", optional: true]}, {:ex_cldr_calendars, "~> 1.22", [hex: :ex_cldr_calendars, repo: "hexpm", optional: false]}, {:ex_cldr_numbers, "~> 2.31", [hex: :ex_cldr_numbers, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:tz, "~> 0.26", [hex: :tz, repo: "hexpm", optional: true]}], "hexpm", "0f2f250d479cadda4e0ef3a5e3d936ae7ba1a3f1199db6791e284e86203495b1"},
|
||||
"ex_cldr_numbers": {:hex, :ex_cldr_numbers, "2.32.3", "b631ff94c982ec518e46bf4736000a30a33d6b58facc085d5f240305f512ad4a", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:digital_token, "~> 0.3 or ~> 1.0", [hex: :digital_token, repo: "hexpm", optional: false]}, {:ex_cldr, "~> 2.37", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:ex_cldr_currencies, ">= 2.14.2", [hex: :ex_cldr_currencies, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "7b626ff1e59a0ec9c3c5db5ce9ca91a6995e2ab56426b71f3cbf67181ea225f5"},
|
||||
"expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"},
|
||||
"file_size": {:hex, :file_size, "3.0.1", "ad447a69442a82fc701765a73992d7b1110136fa0d4a9d3190ea685d60034dcd", [:mix], [{:decimal, ">= 1.0.0 and < 3.0.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:number, "~> 1.0", [hex: :number, repo: "hexpm", optional: false]}], "hexpm", "64dd665bc37920480c249785788265f5d42e98830d757c6a477b3246703b8e20"},
|
||||
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
|
||||
@@ -36,12 +36,12 @@
|
||||
"floki": {:hex, :floki, "0.35.2", "87f8c75ed8654b9635b311774308b2760b47e9a579dabf2e4d5f1e1d42c39e0b", [:mix], [], "hexpm", "6b05289a8e9eac475f644f09c2e4ba7e19201fd002b89c28c1293e7bd16773d9"},
|
||||
"gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"},
|
||||
"gettext": {:hex, :gettext, "0.23.1", "821e619a240e6000db2fc16a574ef68b3bd7fe0167ccc264a81563cc93e67a31", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "19d744a36b809d810d610b57c27b934425859d158ebd56561bc41f7eeb8795db"},
|
||||
"gproc": {:hex, :gproc, "0.8.0", "cea02c578589c61e5341fce149ea36ccef236cc2ecac8691fba408e7ea77ec2f", [:rebar3], [], "hexpm", "580adafa56463b75263ef5a5df4c86af321f68694e7786cb057fd805d1e2a7de"},
|
||||
"grpcbox": {:hex, :grpcbox, "0.16.0", "b83f37c62d6eeca347b77f9b1ec7e9f62231690cdfeb3a31be07cd4002ba9c82", [:rebar3], [{:acceptor_pool, "~> 1.0.0", [hex: :acceptor_pool, repo: "hexpm", optional: false]}, {:chatterbox, "~> 0.13.0", [hex: :ts_chatterbox, repo: "hexpm", optional: false]}, {:ctx, "~> 0.6.0", [hex: :ctx, repo: "hexpm", optional: false]}, {:gproc, "~> 0.8.0", [hex: :gproc, repo: "hexpm", optional: false]}], "hexpm", "294df743ae20a7e030889f00644001370a4f7ce0121f3bbdaf13cf3169c62913"},
|
||||
"gproc": {:hex, :gproc, "0.9.1", "f1df0364423539cf0b80e8201c8b1839e229e5f9b3ccb944c5834626998f5b8c", [:rebar3], [], "hexpm", "905088e32e72127ed9466f0bac0d8e65704ca5e73ee5a62cb073c3117916d507"},
|
||||
"grpcbox": {:hex, :grpcbox, "0.17.1", "6e040ab3ef16fe699ffb513b0ef8e2e896da7b18931a1ef817143037c454bcce", [:rebar3], [{:acceptor_pool, "~> 1.0.0", [hex: :acceptor_pool, repo: "hexpm", optional: false]}, {:chatterbox, "~> 0.15.1", [hex: :ts_chatterbox, repo: "hexpm", optional: false]}, {:ctx, "~> 0.6.0", [hex: :ctx, repo: "hexpm", optional: false]}, {:gproc, "~> 0.9.1", [hex: :gproc, repo: "hexpm", optional: false]}], "hexpm", "4a3b5d7111daabc569dc9cbd9b202a3237d81c80bf97212fbc676832cb0ceb17"},
|
||||
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
|
||||
"hpack": {:hex, :hpack_erl, "0.2.3", "17670f83ff984ae6cd74b1c456edde906d27ff013740ee4d9efaa4f1bf999633", [:rebar3], [], "hexpm", "06f580167c4b8b8a6429040df36cc93bba6d571faeaec1b28816523379cbb23a"},
|
||||
"hpack": {:hex, :hpack_erl, "0.3.0", "2461899cc4ab6a0ef8e970c1661c5fc6a52d3c25580bc6dd204f84ce94669926", [:rebar3], [], "hexpm", "d6137d7079169d8c485c6962dfe261af5b9ef60fbc557344511c1e65e3d95fb0"},
|
||||
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
|
||||
"httpoison": {:hex, :httpoison, "2.1.0", "655fd9a7b0b95ee3e9a3b535cf7ac8e08ef5229bab187fa86ac4208b122d934b", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "fc455cb4306b43827def4f57299b2d5ac8ac331cb23f517e734a4b78210a160c"},
|
||||
"httpoison": {:hex, :httpoison, "2.2.1", "87b7ed6d95db0389f7df02779644171d7319d319178f6680438167d7b69b1f3d", [:mix], [{:hackney, "~> 1.17", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm", "51364e6d2f429d80e14fe4b5f8e39719cacd03eb3f9a9286e61e216feac2d2df"},
|
||||
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
|
||||
"inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"},
|
||||
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
|
||||
@@ -93,13 +93,13 @@
|
||||
"sizeable": {:hex, :sizeable, "1.0.2", "625fe06a5dad188b52121a140286f1a6ae1adf350a942cf419499ecd8a11ee29", [:mix], [], "hexpm", "4bab548e6dfba777b400ca50830a9e3a4128e73df77ab1582540cf5860601762"},
|
||||
"sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"},
|
||||
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
|
||||
"swoosh": {:hex, :swoosh, "1.14.1", "d8813699ba410509008dd3dfdb2df057e3fce367d45d5e6d76b146a7c9d559cd", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "87da72260b4351678f96aec61db5c2acc8a88cda2cf2c4f534eb4c9c461350c7"},
|
||||
"swoosh": {:hex, :swoosh, "1.14.2", "cf686f92ad3b21e6651b20c50eeb1781f581dc7097ef6251b4d322a9f1d19339", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.4 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "01d8fae72930a0b5c1bb9725df0408602ed8c5c3d59dc6e7a39c57b723cd1065"},
|
||||
"tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"},
|
||||
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
|
||||
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
|
||||
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
|
||||
"telemetry_registry": {:hex, :telemetry_registry, "0.3.1", "14a3319a7d9027bdbff7ebcacf1a438f5f5c903057b93aee484cca26f05bdcba", [:mix, :rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "6d0ca77b691cf854ed074b459a93b87f4c7f5512f8f7743c635ca83da81f939e"},
|
||||
"tesla": {:hex, :tesla, "1.7.0", "a62dda2f80d4f8a925eb7b8c5b78c461e0eb996672719fe1a63b26321a5f8b4e", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, "~> 1.3", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.0", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "2e64f01ebfdb026209b47bc651a0e65203fcff4ae79c11efb73c4852b00dc313"},
|
||||
"tesla": {:hex, :tesla, "1.8.0", "d511a4f5c5e42538d97eef7c40ec4f3e44effdc5068206f42ed859e09e51d1fd", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "10501f360cd926a309501287470372af1a6e1cbed0f43949203a4c13300bc79f"},
|
||||
"tls_certificate_check": {:hex, :tls_certificate_check, "1.20.0", "1ac0c53f95e201feb8d398ef9d764ae74175231289d89f166ba88a7f50cd8e73", [:rebar3], [{:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "ab57b74b1a63dc5775650699a3ec032ec0065005eff1f020818742b7312a8426"},
|
||||
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
|
||||
"wallaby": {:hex, :wallaby, "0.30.6", "7dc4c1213f3b52c4152581d126632bc7e06892336d3a0f582853efeeabd45a71", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:httpoison, "~> 0.12 or ~> 1.0 or ~> 2.0", [hex: :httpoison, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix_ecto, ">= 3.0.0", [hex: :phoenix_ecto, repo: "hexpm", optional: true]}, {:web_driver_client, "~> 0.2.0", [hex: :web_driver_client, repo: "hexpm", optional: false]}], "hexpm", "50950c1d968549b54c20e16175c68c7fc0824138e2bb93feb11ef6add8eb23d4"},
|
||||
|
||||
Reference in New Issue
Block a user