chore(Portal): Remove simple forms, change navbar links, fix form styles (#4239)

Closes #4237
Closes #2015

There are new links in the navbar and the floating status badge is
replaced with a link in the burger menu too:


https://github.com/firezone/firezone/assets/1877644/2d72f6d7-a14a-4e56-808d-2e703eca158a
This commit is contained in:
Andrew Dryga
2024-03-25 10:24:24 -06:00
committed by GitHub
parent 486ba52eaf
commit 1cb6ab6dc4
12 changed files with 174 additions and 195 deletions

View File

@@ -48,7 +48,7 @@ defmodule API.MixProject do
{:plug_cowboy, "~> 2.7"},
# Observability deps
{:telemetry_metrics, "~> 0.6"},
{:telemetry_metrics, "~> 1.0"},
{:telemetry_poller, "~> 1.0"},
{:opentelemetry_cowboy, "~> 0.3"},
{:opentelemetry_phoenix, "~> 1.1"},

View File

@@ -65,7 +65,7 @@ defmodule Domain.MixProject do
{:plug, "~> 1.15"},
{:telemetry, "~> 1.0"},
{:telemetry_poller, "~> 1.0"},
{:telemetry_metrics, "~> 0.6.2"},
{:telemetry_metrics, "~> 1.0"},
{:logger_json, "~> 5.1"},
{:recon, "~> 2.5"},
{:observer_cli, "~> 1.7"},

View File

@@ -16,7 +16,7 @@ defmodule Web.CoreComponents do
def logo(assigns) do
~H"""
<a href="https://www.firezone.dev/?utm_source=product" class="flex items-center mb-6 text-2xl">
<a href={~p"/"} class="flex items-center mb-6 text-2xl">
<img src={~p"/images/logo.svg"} class="mr-3 h-8" alt="Firezone Logo" />
<span class="self-center text-2xl font-medium whitespace-nowrap">
Firezone

View File

@@ -119,7 +119,8 @@ defmodule Web.FormComponents do
value={@value}
checked={@checked}
class={[
"rounded border-zinc-300 text-zinc-900",
"bg-neutral-50",
"border border-neutral-300 text-neutral-900 rounded",
"checked:bg-accent-500 checked:hover:bg-accent-500",
@class
]}
@@ -142,7 +143,8 @@ defmodule Web.FormComponents do
class={[
"text-sm bg-neutral-50",
"border border-neutral-300 text-neutral-900 rounded",
"block w-full p-2.5"
"block w-full p-2.5",
@errors != [] && "border-rose-400"
]}
multiple={@multiple}
{@rest}
@@ -174,7 +176,8 @@ defmodule Web.FormComponents do
class={[
"text-sm bg-neutral-50",
"border border-neutral-300 text-neutral-900 rounded",
"block w-full p-2.5"
"block w-full p-2.5",
@errors != [] && "border-rose-400"
]}
multiple={@multiple}
{@rest}
@@ -195,9 +198,11 @@ defmodule Web.FormComponents do
id={@id}
name={@name}
class={[
"mt-2 block w-full rounded text-zinc-900 sm:text-sm sm:leading-6",
"phx-no-feedback:border-zinc-300",
"min-h-[6rem] border-zinc-300",
"mt-2 block w-full rounded sm:text-sm sm:leading-6",
"bg-neutral-50",
"border border-neutral-300 text-neutral-900 rounded",
"phx-no-feedback:border-neutral-300",
"min-h-[6rem] border-neutral-300",
@errors != [] && "border-rose-400"
]}
{@rest}
@@ -551,48 +556,4 @@ defmodule Web.FormComponents do
[text[size], spacing[size]]
end
### Forms ###
@doc """
Renders a simple form.
## Examples
<.simple_form for={@form} phx-change="validate" phx-submit="save">
<.input field={@form[:email]} label="Email"/>
<.input field={@form[:username]} label="Username" />
<:actions>
<.button>Save</.button>
</:actions>
</.simple_form>
"""
attr :for, :any, required: true, doc: "the datastructure for the form"
attr :as, :any, default: nil, doc: "the server side parameter to collect all input under"
attr :rest, :global,
include: ~w(autocomplete name rel action enctype method novalidate target),
doc: "the arbitrary HTML attributes to apply to the form tag"
slot :inner_block, required: true
slot :actions, doc: "the slot for form actions, such as a submit button"
def simple_form(assigns) do
~H"""
<.form :let={f} for={@for} as={@as} {@rest}>
<div class="space-y-8 bg-white">
<%= render_slot(@inner_block, f) %>
<div
:for={action <- @actions}
class={[
"mt-2 flex items-center gap-6",
(length(@actions) > 1 && "justify-between") || "justify-end"
]}
>
<%= render_slot(action, f) %>
</div>
</div>
</.form>
"""
end
end

View File

@@ -76,11 +76,20 @@
<:bottom>
<div class="absolute bottom-0 left-0 justify-left p-4 space-x-4 w-full lg:flex bg-white z-20">
<.link target="_blank" href="https://firezone.statuspage.io">
<.badge>
Platform status
</.badge>
</.link>
<a
target="_blank"
href="https://www.firezone.dev/kb?utm_source=product"
class="text-neutral-700 hover:text-neutral-900 md:hidden"
>
Docs
</a>
<a
target="_blank"
href="https://firezone.statuspage.io"
class="text-neutral-700 hover:text-neutral-900 md:hidden"
>
Status
</a>
</div>
</:bottom>
</.sidebar>

View File

@@ -22,10 +22,7 @@ defmodule Web.NavigationComponents do
<.icon name="hero-bars-3-center-left" class="w-6 h-6" />
<span class="sr-only">Toggle sidebar</span>
</button>
<a
href="https://www.firezone.dev/?utm_source=product"
class="flex items-center justify-between mr-4"
>
<a href={~p"/"} class="flex items-center justify-between mr-4">
<img src={~p"/images/logo.svg"} class="mr-3 h-8" alt="Firezone Logo" />
<span class="self-center text-2xl font-medium whitespace-nowrap">
Firezone
@@ -33,6 +30,21 @@ defmodule Web.NavigationComponents do
</a>
</div>
<div class="flex items-center lg:order-2">
<a
target="_blank"
href="https://www.firezone.dev/kb?utm_source=product"
class="mr-6 mt-1 text-neutral-700 hover:text-neutral-900 md:ml-2 hidden md:block"
>
Docs
</a>
<a
target="_blank"
href="https://firezone.statuspage.io"
class="mr-6 mt-1 text-neutral-700 hover:text-neutral-900 md:ml-2 hidden md:block"
>
Status
</a>
<.dropdown id="user-menu">
<:button>
<span class="sr-only">Open user menu</span>

View File

@@ -13,7 +13,7 @@ defmodule Web.Policies.Edit do
socket =
assign(socket,
page_title: "Edit #{policy.id}",
page_title: "Edit Policy #{policy.id}",
policy: policy,
form: form
)
@@ -37,29 +37,25 @@ defmodule Web.Policies.Edit do
</.breadcrumbs>
<.section>
<:title><%= "#{@page_title}: #{@policy.id}" %></:title>
<:title><%= @page_title %></:title>
<:content>
<div class="max-w-2xl px-4 py-8 mx-auto lg:py-16">
<h2 class="mb-4 text-xl text-neutral-900">Edit Policy details</h2>
<.simple_form
for={@form}
class="space-y-4 lg:space-y-6"
phx-submit="submit"
phx-change="validate"
>
<.input
field={@form[:description]}
type="textarea"
label="Policy Description"
placeholder="Enter a policy description here"
phx-debounce="300"
/>
<:actions>
<.submit_button phx-disable-with="Updating Policy...">
Save
</.submit_button>
</:actions>
</.simple_form>
<.form for={@form} class="space-y-4 lg:space-y-6" phx-submit="submit" phx-change="validate">
<div class="grid gap-4 mb-4 sm:grid-cols-1 sm:gap-6 sm:mb-6">
<.input
field={@form[:description]}
type="textarea"
label="Policy Description"
placeholder="Enter a policy description here"
phx-debounce="300"
/>
</div>
<.submit_button phx-disable-with="Updating Policy...">
Save
</.submit_button>
</.form>
</div>
</:content>
</.section>

View File

@@ -53,53 +53,49 @@ defmodule Web.Policies.New do
</p>
</div>
<.simple_form
:if={@actor_groups != []}
for={@form}
phx-submit="submit"
phx-change="validate"
>
<.form :if={@actor_groups != []} for={@form} phx-submit="submit" phx-change="validate">
<.base_error form={@form} field={:base} />
<.input
field={@form[:actor_group_id]}
label="Group"
type="group_select"
options={Web.Groups.Components.select_options(@actor_groups)}
value={@actor_group_id || @form[:actor_group_id].value}
disabled={not is_nil(@actor_group_id)}
required
/>
<.input
field={@form[:resource_id]}
label="Resource"
type="select"
options={
Enum.map(@resources, fn resource ->
group_names = resource.gateway_groups |> Enum.map(& &1.name)
<div class="grid gap-4 mb-4 sm:grid-cols-1 sm:gap-6 sm:mb-6">
<.input
field={@form[:actor_group_id]}
label="Group"
type="group_select"
options={Web.Groups.Components.select_options(@actor_groups)}
value={@actor_group_id || @form[:actor_group_id].value}
disabled={not is_nil(@actor_group_id)}
required
/>
<.input
field={@form[:resource_id]}
label="Resource"
type="select"
options={
Enum.map(@resources, fn resource ->
group_names = resource.gateway_groups |> Enum.map(& &1.name)
[
key: "#{resource.name} - #{Enum.join(group_names, ",")}",
value: resource.id
]
end)
}
value={@resource_id || @form[:resource_id].value}
disabled={not is_nil(@resource_id)}
required
/>
<.input
field={@form[:description]}
type="textarea"
label="Description"
placeholder="Enter a reason for creating a policy here"
phx-debounce="300"
/>
<:actions>
<.button phx-disable-with="Creating Policy..." class="w-full">
Create Policy
</.button>
</:actions>
</.simple_form>
[
key: "#{resource.name} - #{Enum.join(group_names, ",")}",
value: resource.id
]
end)
}
value={@resource_id || @form[:resource_id].value}
disabled={not is_nil(@resource_id)}
required
/>
<.input
field={@form[:description]}
type="textarea"
label="Description"
placeholder="Enter a reason for creating a policy here"
phx-debounce="300"
/>
</div>
<.submit_button phx-disable-with="Creating Policy..." class="w-full">
Create Policy
</.submit_button>
</.form>
</div>
</:content>
</.section>

View File

@@ -109,9 +109,13 @@ defmodule Web.SignIn do
<div :if={Web.Auth.fetch_auth_context_type!(@params) == :browser} class="mx-auto p-6 sm:p-8">
<p class="py-2">
Meant to sign in from a client instead?
<.website_link href="/kb/user-guides">
Read the docs.
</.website_link>
<.website_link href="/kb/user-guides">Read the docs.</.website_link>
</p>
<p class="py-2">
Looking for a different account?
<.link navigate={~p"/"} class={[link_style()]}>
See recently used accounts.
</.link>
</p>
</div>
</div>
@@ -156,37 +160,37 @@ defmodule Web.SignIn do
assigns = Map.put(assigns, :userpass_form, form)
~H"""
<.simple_form
<.form
for={@userpass_form}
action={~p"/#{@account}/sign_in/providers/#{@provider.id}/verify_credentials"}
class="space-y-4 lg:space-y-6"
id="userpass_form"
phx-update="ignore"
>
<.input :for={{key, value} <- @params} type="hidden" name={key} value={value} />
<div class="bg-white grid gap-4 mb-4 sm:grid-cols-1 sm:gap-6 sm:mb-6">
<.input :for={{key, value} <- @params} type="hidden" name={key} value={value} />
<.input
field={@userpass_form[:provider_identifier]}
type="text"
label="Username"
placeholder="Enter your username"
required
/>
<.input
field={@userpass_form[:provider_identifier]}
type="text"
label="Username"
placeholder="Enter your username"
required
/>
<.input
field={@userpass_form[:secret]}
type="password"
label="Password"
placeholder="••••••••"
required
/>
<.input
field={@userpass_form[:secret]}
type="password"
label="Password"
placeholder="••••••••"
required
/>
</div>
<:actions>
<.button phx-disable-with="Signing in..." class="w-full">
Sign in
</.button>
</:actions>
</.simple_form>
<.button phx-disable-with="Signing in..." class="w-full">
Sign in
</.button>
</.form>
"""
end
@@ -196,7 +200,7 @@ defmodule Web.SignIn do
assigns = Map.put(assigns, :email_form, form)
~H"""
<.simple_form
<.form
for={@email_form}
action={~p"/#{@account}/sign_in/providers/#{@provider.id}/request_magic_link"}
class="space-y-4 lg:space-y-6"
@@ -212,10 +216,10 @@ defmodule Web.SignIn do
placeholder="Enter your email"
required
/>
<.button phx-disable-with="Sending..." class="w-full" style="info">
<.submit_button phx-disable-with="Sending..." class="w-full" style="info">
Request sign in token
</.button>
</.simple_form>
</.submit_button>
</.form>
"""
end

View File

@@ -202,53 +202,54 @@ defmodule Web.SignUp do
<h3 class="text-center text-m leading-tight tracking-tight text-neutral-900 sm:text-xl">
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]}>
<.form for={@form} class="space-y-4 lg:space-y-6" phx-submit="submit" phx-change="validate">
<div class="bg-white grid gap-4 mb-4 sm:grid-cols-1 sm:gap-6 sm:mb-6">
<.input
field={account[:name]}
field={@form[:email]}
type="text"
label="Account Name"
placeholder="Enter an account name"
label="Email"
placeholder="Enter your work email here"
required
autofocus
phx-debounce="300"
/>
<.input field={account[:slug]} type="hidden" />
</.inputs_for>
<.inputs_for :let={actor} field={@form[:actor]}>
<.input
field={actor[:name]}
type="text"
label="Your Name"
placeholder="Enter your name here"
required
phx-debounce="300"
/>
<.input field={actor[:type]} type="hidden" />
</.inputs_for>
<.inputs_for :let={account} field={@form[:account]}>
<.input
field={account[:name]}
type="text"
label="Account Name"
placeholder="Enter an account name"
required
phx-debounce="300"
/>
<.input field={account[:slug]} type="hidden" />
</.inputs_for>
<.inputs_for :let={actor} field={@form[:actor]}>
<.input
field={actor[:name]}
type="text"
label="Your Name"
placeholder="Enter your name here"
required
phx-debounce="300"
/>
<.input field={actor[:type]} type="hidden" />
</.inputs_for>
</div>
<.button phx-disable-with="Creating Account..." class="w-full">
Create Account
</.button>
<:actions>
<.button phx-disable-with="Creating Account..." class="w-full">
Create Account
</.button>
</:actions>
<p class="text-xs text-center">
By signing up you agree to our <.link
href="https://www.firezone.dev/terms"
class={link_style()}
>Terms of Use</.link>.
</p>
</.simple_form>
</.form>
"""
end

View File

@@ -56,7 +56,7 @@ defmodule Web.MixProject do
{:tailwind, "~> 0.2.0", runtime: Mix.env() == :dev},
# Observability and debugging deps
{:telemetry_metrics, "~> 0.6"},
{:telemetry_metrics, "~> 1.0"},
{:telemetry_poller, "~> 1.0"},
{:recon, "~> 2.5"},
{:observer_cli, "~> 1.7"},

View File

@@ -54,7 +54,7 @@
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"},
"mix_audit": {:hex, :mix_audit, "2.1.2", "6cd5c5e2edbc9298629c85347b39fb3210656e541153826efd0b2a63767f3395", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.9", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "68d2f06f96b9c445a23434c9d5f09682866a5b4e90f631829db1c64f140e795b"},
"mix_audit": {:hex, :mix_audit, "2.1.3", "c70983d5cab5dca923f9a6efe559abfb4ec3f8e87762f02bab00fa4106d17eda", [:make, :mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.9", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "8c3987100b23099aea2f2df0af4d296701efd031affb08d0746b2be9e35988ec"},
"multipart": {:hex, :multipart, "0.4.0", "634880a2148d4555d050963373d0e3bbb44a55b2badd87fa8623166172e9cda0", [:mix], [{:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm", "3c5604bc2fb17b3137e5d2abdf5dacc2647e60c5cc6634b102cf1aef75a06f0a"},
"nimble_csv": {:hex, :nimble_csv, "1.2.0", "4e26385d260c61eba9d4412c71cea34421f296d5353f914afe3f2e71cce97722", [:mix], [], "hexpm", "d0628117fcc2148178b034044c55359b26966c6eaa8e2ce15777be3bbc91b12a"},
"nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"},
@@ -97,12 +97,12 @@
"swoosh": {:hex, :swoosh, "1.16.3", "4ab7dc429e84afaf8ffe1c7c06ce1acbc7ddde758d2cb9152dd2ac32289d5498", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {: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]}, {:mua, "~> 0.1.0", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {: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", "ff70980087650a72951ebd109a286d83c270e2b6610aba447140562adff8cf0a"},
"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.2", "2caabe9344ec17eafe5403304771c3539f3b6e2f7fb6a6f602558c825d0d0bfb", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9b43db0dc33863930b9ef9d27137e78974756f5f198cae18409970ed6fa5b561"},
"telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"},
"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.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"},
"thousand_island": {:hex, :thousand_island, "1.3.5", "6022b6338f1635b3d32406ff98d68b843ba73b3aa95cfc27154223244f3a6ca5", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2be6954916fdfe4756af3239fb6b6d75d0b8063b5df03ba76fd8a4c87849e180"},
"tls_certificate_check": {:hex, :tls_certificate_check, "1.21.0", "042ab2c0c860652bc5cf69c94e3a31f96676d14682e22ec7813bd173ceff1788", [:rebar3], [{:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "6cee6cffc35a390840d48d463541d50746a7b0e421acaadb833cfc7961e490e7"},
"tls_certificate_check": {:hex, :tls_certificate_check, "1.22.1", "0f450cc1568a67a65ce5e15df53c53f9a098c3da081c5f126199a72505858dc1", [:rebar3], [{:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "3092be0babdc0e14c2e900542351e066c0fa5a9cf4b3597559ad1e67f07938c0"},
"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"},
"web_driver_client": {:hex, :web_driver_client, "0.2.0", "63b76cd9eb3b0716ec5467a0f8bead73d3d9612e63f7560d21357f03ad86e31a", [:mix], [{:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.3", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "83cc6092bc3e74926d1c8455f0ce927d5d1d36707b74d9a65e38c084aab0350f"},