Update to Phoenix 1.7

This commit is contained in:
Chris McCord 2022-11-17 10:01:20 -05:00
parent 6b02cfc614
commit 7bbce31bb9
35 changed files with 273 additions and 890 deletions

View file

@ -1,6 +1,6 @@
import "phoenix_html" import "phoenix_html"
import {Socket} from "phoenix" import {Socket} from "phoenix"
import {LiveSocket} from "phoenix_live_view" import {LiveSocket} from "./phoenix_live_view"
import topbar from "../vendor/topbar" import topbar from "../vendor/topbar"
let nowSeconds = () => Math.round(Date.now() / 1000) let nowSeconds = () => Math.round(Date.now() / 1000)
@ -187,7 +187,7 @@ Hooks.Ping = {
this.handleEvent("pong", () => { this.handleEvent("pong", () => {
let rtt = Date.now() - this.nowMs let rtt = Date.now() - this.nowMs
this.el.innerText = `ping: ${rtt}ms` this.el.innerText = `ping: ${rtt}ms`
this.timer = setTimeout(() => this.ping(rtt), 1000) // this.timer = setTimeout(() => this.ping(rtt), 1000)
}) })
this.ping(null) this.ping(null)
}, },

View file

@ -1 +0,0 @@
/Users/chris/oss/phoenix/assets/js/phoenix

View file

@ -17,32 +17,11 @@ config :live_beats, :files, admin_usernames: []
config :live_beats, LiveBeatsWeb.Endpoint, config :live_beats, LiveBeatsWeb.Endpoint,
url: [host: "localhost"], url: [host: "localhost"],
secret_key_base: "55naB2xjgnsDeN+kKz7xoeqx3vIPcpCkAmg+CoVR/F7iZ5MQgNE6ykiNXoFa7wcC", secret_key_base: "55naB2xjgnsDeN+kKz7xoeqx3vIPcpCkAmg+CoVR/F7iZ5MQgNE6ykiNXoFa7wcC",
render_errors: [view: LiveBeatsWeb.ErrorView, accepts: ~w(html json), layout: false],
pubsub_server: LiveBeats.PubSub, pubsub_server: LiveBeats.PubSub,
live_view: [signing_salt: "OHBVr+w4"] live_view: [signing_salt: "OHBVr+w4"],
render_errors: [
# Configures the mailer formats: [html: LiveBeatsWeb.ErrorHTML, json: LiveBeatsWeb.ErrorJSON],
# layout: false
# By default it uses the "Local" adapter which stores the emails
# locally. You can see the emails in your browser, at "/dev/mailbox".
#
# For production it's recommended to configure a different adapter
# at the `config/runtime.exs`.
config :live_beats, LiveBeats.Mailer, adapter: Swoosh.Adapters.Local
# Swoosh API client is needed for adapters other than SMTP.
config :swoosh, :api_client, false
# Configure esbuild (the version is required)
config :tailwind,
version: "3.0.10",
default: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/assets/app.css
),
cd: Path.expand("../assets", __DIR__)
] ]
config :esbuild, config :esbuild,
@ -53,6 +32,18 @@ config :esbuild,
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
] ]
# Configure tailwind (the version is required)
config :tailwind,
version: "3.1.8",
default: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/assets/app.css
),
cd: Path.expand("../assets", __DIR__)
]
# Configures Elixir's Logger # Configures Elixir's Logger
config :logger, :console, config :logger, :console,
format: "$time $metadata[$level] $message\n", format: "$time $metadata[$level] $message\n",

View file

@ -102,3 +102,6 @@ config :phoenix, :stacktrace_depth, 20
# Initialize plugs at runtime for faster development compilation # Initialize plugs at runtime for faster development compilation
config :phoenix, :plug_init_mode, :runtime config :phoenix, :plug_init_mode, :runtime
# Disable swoosh api client as it is only required for production adapters.
config :swoosh, :api_client, false

View file

@ -16,6 +16,8 @@ config :live_beats, LiveBeatsWeb.Endpoint,
# Do not print debug messages in production # Do not print debug messages in production
config :logger, level: :info config :logger, level: :info
config :swoosh, :api_client, LiveBeats.Finch
# ## SSL Support # ## SSL Support
# #
# To get SSL working, you will need to add the `https` key # To get SSL working, you will need to add the `https` key

View file

@ -36,11 +36,11 @@ config :live_beats, LiveBeatsWeb.Endpoint,
http: [ip: {127, 0, 0, 1}, port: 4002], http: [ip: {127, 0, 0, 1}, port: 4002],
server: false server: false
# In test we don't send emails.
config :live_beats, LiveBeats.Mailer, adapter: Swoosh.Adapters.Test
# Print only warnings and errors during test # Print only warnings and errors during test
config :logger, level: :warn config :logger, level: :warn
# Initialize plugs at runtime for faster test compilation # Initialize plugs at runtime for faster test compilation
config :phoenix, :plug_init_mode, :runtime config :phoenix, :plug_init_mode, :runtime
# Disable swoosh api client as it is only required for production adapters.
config :swoosh, :api_client, false

View file

@ -22,6 +22,7 @@ defmodule LiveBeats.Application do
{Phoenix.PubSub, name: LiveBeats.PubSub}, {Phoenix.PubSub, name: LiveBeats.PubSub},
# start presence # start presence
LiveBeatsWeb.Presence, LiveBeatsWeb.Presence,
{Finch, name: LiveBeats.Finch},
# Start the Endpoint (http/https) # Start the Endpoint (http/https)
LiveBeatsWeb.Endpoint, LiveBeatsWeb.Endpoint,
# Expire songs every six hours # Expire songs every six hours

View file

@ -5,7 +5,7 @@ defmodule LiveBeats.MP3Stat do
MP3 decoding and duration calculation credit to: MP3 decoding and duration calculation credit to:
https://shadowfacts.net/2021/mp3-duration/ https://shadowfacts.net/2021/mp3-duration/
""" """
use Bitwise import Bitwise
alias LiveBeats.MP3Stat alias LiveBeats.MP3Stat
defstruct duration: 0, size: 0, path: nil, title: nil, artist: nil, tags: nil defstruct duration: 0, size: 0, path: nil, title: nil, artist: nil, tags: nil

View file

@ -6,7 +6,7 @@ defmodule LiveBeatsWeb do
This can be used in your application as: This can be used in your application as:
use LiveBeatsWeb, :controller use LiveBeatsWeb, :controller
use LiveBeatsWeb, :view use LiveBeatsWeb, :html
The definitions below will be executed for every view, The definitions below will be executed for every view,
controller, etc, so keep them short and clean, focused controller, etc, so keep them short and clean, focused
@ -17,9 +17,14 @@ defmodule LiveBeatsWeb do
and import those modules here. and import those modules here.
""" """
def static_paths, do: ~w(assets fonts images favicon.ico robots.txt)
def controller do def controller do
quote do quote do
use Phoenix.Controller, namespace: LiveBeatsWeb use Phoenix.Controller,
namespace: LiveBeatsWeb,
formats: [:html, :json],
layouts: [html: LiveBeatsWeb.Layouts]
import Plug.Conn import Plug.Conn
import LiveBeatsWeb.Gettext import LiveBeatsWeb.Gettext
@ -27,18 +32,25 @@ defmodule LiveBeatsWeb do
end end
end end
def view do def html do
quote do quote do
use Phoenix.View, use Phoenix.Component
root: "lib/live_beats_web/templates",
namespace: LiveBeatsWeb
# Import convenience functions from controllers # Import convenience functions from controllers
import Phoenix.Controller, import Phoenix.Controller,
only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1] only: [get_csrf_token: 0, view_module: 1, view_template: 1]
# Include shared imports and aliases for views # Include general helpers for rendering HTML
unquote(view_helpers()) unquote(html_helpers())
end
end
def verified_routes do
quote do
use Phoenix.VerifiedRoutes,
endpoint: LiveBeatsWeb.Endpoint,
router: LiveBeatsWeb.Router,
statics: LiveBeatsWeb.static_paths()
end end
end end
@ -46,14 +58,14 @@ defmodule LiveBeatsWeb do
quote do quote do
@opts Keyword.merge( @opts Keyword.merge(
[ [
layout: {LiveBeatsWeb.LayoutView, "live.html"}, layout: {LiveBeatsWeb.Layouts, :live},
container: {:div, class: "relative h-screen flex overflow-hidden bg-white"} container: {:div, class: "relative h-screen flex overflow-hidden bg-white"}
], ],
unquote(opts) unquote(opts)
) )
use Phoenix.LiveView, @opts use Phoenix.LiveView, @opts
unquote(view_helpers()) unquote(html_helpers())
end end
end end
@ -61,7 +73,7 @@ defmodule LiveBeatsWeb do
quote do quote do
use Phoenix.LiveComponent use Phoenix.LiveComponent
unquote(view_helpers()) unquote(html_helpers())
end end
end end
@ -82,19 +94,15 @@ defmodule LiveBeatsWeb do
end end
end end
defp view_helpers do defp html_helpers do
quote do quote do
# Use all HTML functionality (forms, tags, etc) # Use all HTML functionality (forms, tags, etc)
use Phoenix.HTML use Phoenix.HTML
# Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc) # Import LiveView and .heex helpers (live_render, live_patch, <.form>, etc)
import Phoenix.LiveView.Helpers use Phoenix.Component
# Import basic rendering functionality (render, render_layout, etc) import LiveBeatsWeb.CoreComponents
import Phoenix.View
import LiveBeatsWeb.ErrorHelpers
import LiveBeatsWeb.LiveHelpers
import LiveBeatsWeb.Gettext import LiveBeatsWeb.Gettext
alias LiveBeatsWeb.Router.Helpers, as: Routes alias LiveBeatsWeb.Router.Helpers, as: Routes
alias Phoenix.LiveView.JS alias Phoenix.LiveView.JS

View file

@ -12,8 +12,7 @@ defmodule LiveBeatsWeb.Presence do
@pubsub LiveBeats.PubSub @pubsub LiveBeats.PubSub
import Phoenix.LiveView.Helpers use LiveBeatsWeb, :html
import LiveBeatsWeb.LiveHelpers
alias LiveBeats.{Accounts, MediaLibrary} alias LiveBeats.{Accounts, MediaLibrary}
alias LiveBeatsWeb.Presence.BadgeComponent alias LiveBeatsWeb.Presence.BadgeComponent
@ -81,7 +80,6 @@ defmodule LiveBeatsWeb.Presence do
end end
def listening_now(assigns) do def listening_now(assigns) do
import Phoenix.LiveView
count = Enum.count(assigns.presence_ids) count = Enum.count(assigns.presence_ids)
assigns = assigns =

View file

@ -1,4 +1,4 @@
defmodule LiveBeatsWeb.LiveHelpers do defmodule LiveBeatsWeb.CoreComponents do
use Phoenix.Component use Phoenix.Component
alias LiveBeatsWeb.Router.Helpers, as: Routes alias LiveBeatsWeb.Router.Helpers, as: Routes
@ -24,6 +24,8 @@ defmodule LiveBeatsWeb.LiveHelpers do
profile_path(profile.username, action) profile_path(profile.username, action)
end end
slot :inner_block
def connection_status(assigns) do def connection_status(assigns) do
~H""" ~H"""
<div <div
@ -62,12 +64,12 @@ defmodule LiveBeatsWeb.LiveHelpers do
end end
attr :flash, :map attr :flash, :map
attr :kiny, :atom attr :kind, :atom
def flash(%{kind: :error} = assigns) do def flash(%{kind: :error} = assigns) do
~H""" ~H"""
<%= if live_flash(@flash, @kind) do %>
<div <div
:if={msg = Phoenix.Flash.get(@flash, @kind)}
id="flash" id="flash"
class="rounded-md bg-red-50 p-4 fixed top-1 right-1 w-96 fade-in-scale z-50" class="rounded-md bg-red-50 p-4 fixed top-1 right-1 w-96 fade-in-scale z-50"
phx-click={ phx-click={
@ -80,7 +82,7 @@ defmodule LiveBeatsWeb.LiveHelpers do
<div class="flex justify-between items-center space-x-3 text-red-700"> <div class="flex justify-between items-center space-x-3 text-red-700">
<.icon name={:exclamation_circle} class="w-5 w-5" /> <.icon name={:exclamation_circle} class="w-5 w-5" />
<p class="flex-1 text-sm font-medium" role="alert"> <p class="flex-1 text-sm font-medium" role="alert">
<%= live_flash(@flash, @kind) %> <%= msg %>
</p> </p>
<button <button
type="button" type="button"
@ -90,14 +92,13 @@ defmodule LiveBeatsWeb.LiveHelpers do
</button> </button>
</div> </div>
</div> </div>
<% end %>
""" """
end end
def flash(%{kind: :info} = assigns) do def flash(%{kind: :info} = assigns) do
~H""" ~H"""
<%= if live_flash(@flash, @kind) do %>
<div <div
:if={msg = Phoenix.Flash.get(@flash, @kind)}
id="flash" id="flash"
class="rounded-md bg-green-50 p-4 fixed top-1 right-1 w-96 fade-in-scale z-50" class="rounded-md bg-green-50 p-4 fixed top-1 right-1 w-96 fade-in-scale z-50"
phx-click={JS.push("lv:clear-flash") |> JS.remove_class("fade-in-scale") |> hide("#flash")} phx-click={JS.push("lv:clear-flash") |> JS.remove_class("fade-in-scale") |> hide("#flash")}
@ -107,7 +108,7 @@ defmodule LiveBeatsWeb.LiveHelpers do
<div class="flex justify-between items-center space-x-3 text-green-700"> <div class="flex justify-between items-center space-x-3 text-green-700">
<.icon name={:check_circle} class="w-5 h-5" /> <.icon name={:check_circle} class="w-5 h-5" />
<p class="flex-1 text-sm font-medium" role="alert"> <p class="flex-1 text-sm font-medium" role="alert">
<%= live_flash(@flash, @kind) %> <%= msg %>
</p> </p>
<button <button
type="button" type="button"
@ -117,7 +118,6 @@ defmodule LiveBeatsWeb.LiveHelpers do
</button> </button>
</div> </div>
</div> </div>
<% end %>
""" """
end end
@ -180,11 +180,18 @@ defmodule LiveBeatsWeb.LiveHelpers do
</.dropdown> </.dropdown>
""" """
attr :id, :string, required: true attr :id, :string, required: true
attr :ok, :string, required: true
attr :img, :list, default: [] slot :img do
attr :title, :list, default: [] attr :src, :string
attr :subtitle, :list, default: [] end
attr :link, :list, default: []
slot :title
slot :subtitle
slot :link do
attr :navigate, :string
attr :href, :string
attr :method, :any
end
def dropdown(assigns) do def dropdown(assigns) do
~H""" ~H"""
@ -364,12 +371,12 @@ defmodule LiveBeatsWeb.LiveHelpers do
attr :navigate, :string, default: nil attr :navigate, :string, default: nil
attr :on_cancel, JS, default: %JS{} attr :on_cancel, JS, default: %JS{}
attr :on_confirm, JS, default: %JS{} attr :on_confirm, JS, default: %JS{}
# slots
attr :title, :list, default: []
attr :confirm, :list, default: []
attr :cancel, :list, default: []
attr :rest, :global attr :rest, :global
slot :title
slot :confirm
slot :cancel
def modal(assigns) do def modal(assigns) do
~H""" ~H"""
<div <div
@ -377,7 +384,7 @@ defmodule LiveBeatsWeb.LiveHelpers do
class={"fixed z-10 inset-0 overflow-y-auto #{if @show, do: "fade-in", else: "hidden"}"} class={"fixed z-10 inset-0 overflow-y-auto #{if @show, do: "fade-in", else: "hidden"}"}
{@rest} {@rest}
> >
<.focus_wrap id={"#{@id}-focus-wrap"} content={"##{@id}-container"}> <.focus_wrap id={"#{@id}-focus-wrap"}>
<div <div
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0" class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
aria-labelledby={"#{@id}-title"} aria-labelledby={"#{@id}-title"}
@ -477,7 +484,7 @@ defmodule LiveBeatsWeb.LiveHelpers do
""" """
end end
attr :actions, :list, default: [] slot :actions
def title_bar(assigns) do def title_bar(assigns) do
~H""" ~H"""
@ -501,6 +508,8 @@ defmodule LiveBeatsWeb.LiveHelpers do
attr :primary, :boolean, default: false attr :primary, :boolean, default: false
attr :rest, :global attr :rest, :global
slot :inner_block
def button(%{patch: _} = assigns) do def button(%{patch: _} = assigns) do
~H""" ~H"""
<%= if @primary do %> <%= if @primary do %>
@ -541,8 +550,8 @@ defmodule LiveBeatsWeb.LiveHelpers do
attr :row_id, :any, default: false attr :row_id, :any, default: false
attr :rows, :list, required: true attr :rows, :list, required: true
# slots
attr :col, :list, required: true slot :col, required: true
def table(assigns) do def table(assigns) do
assigns = assigns =
@ -590,8 +599,11 @@ defmodule LiveBeatsWeb.LiveHelpers do
attr :rows, :list, required: true attr :rows, :list, required: true
attr :owns_profile?, :boolean, default: false attr :owns_profile?, :boolean, default: false
attr :active_id, :any, default: nil attr :active_id, :any, default: nil
# slots
attr :col, :list slot :col do
attr :label, :string
attr :class, :string
end
def live_table(assigns) do def live_table(assigns) do
assigns = assign(assigns, :col, for(col <- assigns.col, col[:if] != false, do: col)) assigns = assign(assigns, :col, for(col <- assigns.col, col[:if] != false, do: col))
@ -648,4 +660,72 @@ defmodule LiveBeatsWeb.LiveHelpers do
|> JS.dispatch("js:focus-closest", to: to) |> JS.dispatch("js:focus-closest", to: to)
|> hide(to) |> hide(to)
end end
@doc """
Generates tag for inlined form input errors.
"""
def error_tag(form, field) do
error(%{
errors: form.errors,
field: field,
input_name: Phoenix.HTML.Form.input_name(form, field)
})
end
def error(%{errors: errors, field: field} = assigns) do
assigns =
assigns
|> assign(:error_values, Keyword.get_values(errors, field))
|> assign_new(:class, fn -> "" end)
~H"""
<%= for error <- @error_values do %>
<span
phx-feedback-for={@input_name}
class={
"invalid-feedback inline-block pl-2 pr-2 text-sm text-white bg-red-600 rounded-md #{@class}"
}
>
<%= translate_error(error) %>
</span>
<% end %>
<%= if Enum.empty?(@error_values) do %>
<span class={"invalid-feedback inline-block h-0 #{@class}"}></span>
<% end %>
"""
end
@doc """
Translates an error message using gettext.
"""
def translate_error({msg, opts}) do
# When using gettext, we typically pass the strings we want
# to translate as a static argument:
#
# # Translate "is invalid" in the "errors" domain
# dgettext("errors", "is invalid")
#
# # Translate the number of files with plural rules
# dngettext("errors", "1 file", "%{count} files", count)
#
# Because the error messages we show in our forms and APIs
# are defined inside Ecto, we need to translate them dynamically.
# This requires us to call the Gettext module passing our gettext
# backend as first argument.
#
# Note we use the "errors" domain, which means translations
# should be written to the errors.po file. The :count option is
# set by Ecto and indicates we should also apply plural rules.
if count = opts[:count] do
Gettext.dngettext(LiveBeatsWeb.Gettext, "errors", msg, msg, count, opts)
else
Gettext.dgettext(LiveBeatsWeb.Gettext, "errors", msg, opts)
end
end
def translate_changeset_errors(changeset) do
changeset.errors
|> Enum.map(fn {key, value} -> "#{key} #{translate_error(value)}" end)
|> Enum.join("\n")
end
end end

View file

@ -1,13 +1,13 @@
defmodule LiveBeatsWeb.LayoutView do defmodule LiveBeatsWeb.Layouts do
use LiveBeatsWeb, :view use LiveBeatsWeb, :html
use Phoenix.Component
# Phoenix LiveDashboard is available only in development by default,
# so we instruct Elixir to not warn if the dashboard route is missing.
@compile {:no_warn_undefined, {Routes, :live_dashboard_path, 2}}
alias LiveBeatsWeb.Endpoint alias LiveBeatsWeb.Endpoint
embed_templates "layouts/*"
attr :id, :string
attr :users, :list
def sidebar_active_users(assigns) do def sidebar_active_users(assigns) do
~H""" ~H"""
<div class="mt-8"> <div class="mt-8">
@ -31,6 +31,10 @@ defmodule LiveBeatsWeb.LayoutView do
""" """
end end
attr :id, :string
attr :current_user, :any
attr :active_tab, :atom
def sidebar_nav_links(assigns) do def sidebar_nav_links(assigns) do
~H""" ~H"""
<div class="space-y-1"> <div class="space-y-1">
@ -90,9 +94,11 @@ defmodule LiveBeatsWeb.LayoutView do
""" """
end end
attr :id, :string
attr :current_user, :any
def sidebar_account_dropdown(assigns) do def sidebar_account_dropdown(assigns) do
~H""" ~H"""
<.dropdown id={@id} foo="bar"> <.dropdown id={@id}>
<:img src={@current_user.avatar_url} /> <:img src={@current_user.avatar_url} />
<:title><%= @current_user.name %></:title> <:title><%= @current_user.name %></:title>
<:subtitle>@<%= @current_user.username %></:subtitle> <:subtitle>@<%= @current_user.username %></:subtitle>

View file

@ -0,0 +1,5 @@
<main>
<p class="alert alert-info" role="alert"><%= Phoenix.Flash.get(@flash, :info) %></p>
<p class="alert alert-danger" role="alert"><%= Phoenix.Flash.get(@flash, :error) %></p>
<%= @inner_content %>
</main>

View file

@ -0,0 +1,7 @@
defmodule LiveBeatsWeb.ErrorHTML do
use LiveBeatsWeb, :html
def template_not_found(template, _assigns) do
Phoenix.Controller.status_message_from_template(template)
end
end

View file

@ -1,7 +0,0 @@
defmodule LiveBeatsWeb.PageController do
use LiveBeatsWeb, :controller
def index(conn, _params) do
render(conn, "index.html")
end
end

View file

@ -9,10 +9,10 @@ defmodule LiveBeatsWeb.UserAuth do
def on_mount(:current_user, _params, session, socket) do def on_mount(:current_user, _params, session, socket) do
case session do case session do
%{"user_id" => user_id} -> %{"user_id" => user_id} ->
{:cont, LiveView.assign_new(socket, :current_user, fn -> Accounts.get_user(user_id) end)} {:cont, Phoenix.Component.assign_new(socket, :current_user, fn -> Accounts.get_user(user_id) end)}
%{} -> %{} ->
{:cont, LiveView.assign(socket, :current_user, nil)} {:cont, Phoenix.Component.assign(socket, :current_user, nil)}
end end
end end
@ -20,7 +20,7 @@ defmodule LiveBeatsWeb.UserAuth do
case session do case session do
%{"user_id" => user_id} -> %{"user_id" => user_id} ->
new_socket = new_socket =
LiveView.assign_new(socket, :current_user, fn -> Accounts.get_user!(user_id) end) Phoenix.Component.assign_new(socket, :current_user, fn -> Accounts.get_user!(user_id) end)
%Accounts.User{} = new_socket.assigns.current_user %Accounts.User{} = new_socket.assigns.current_user
{:cont, new_socket} {:cont, new_socket}
@ -145,6 +145,6 @@ defmodule LiveBeatsWeb.UserAuth do
defp maybe_store_return_to(conn), do: conn defp maybe_store_return_to(conn), do: conn
def signed_in_path(conn) do def signed_in_path(conn) do
LiveBeatsWeb.LiveHelpers.profile_path(conn.assigns.current_user) LiveBeatsWeb.CoreComponents.profile_path(conn.assigns.current_user)
end end
end end

View file

@ -20,7 +20,7 @@ defmodule LiveBeatsWeb.Endpoint do
at: "/", at: "/",
from: :live_beats, from: :live_beats,
gzip: false, gzip: false,
only: ~w(assets fonts images favicon.ico robots.txt uploads) only: LiveBeatsWeb.static_paths()
# Code reloading can be explicitly enabled under the # Code reloading can be explicitly enabled under the
# :code_reloader configuration of your endpoint. # :code_reloader configuration of your endpoint.

View file

@ -1,5 +1,6 @@
defmodule LiveBeatsWeb.Nav do defmodule LiveBeatsWeb.Nav do
import Phoenix.LiveView import Phoenix.LiveView
use Phoenix.Component
alias LiveBeats.{Accounts, MediaLibrary} alias LiveBeats.{Accounts, MediaLibrary}
alias LiveBeatsWeb.{ProfileLive, SettingsLive} alias LiveBeatsWeb.{ProfileLive, SettingsLive}

View file

@ -185,6 +185,7 @@ defmodule LiveBeatsWeb.PlayerLive do
socket = socket =
socket socket
|> assign( |> assign(
foo: true,
song: nil, song: nil,
playing: false, playing: false,
profile: nil, profile: nil,

View file

@ -95,7 +95,7 @@ defmodule LiveBeatsWeb.ProfileLive do
<%= song.attribution %> <%= song.attribution %>
</:col> </:col>
<:col :let={%{song: song}} label="Duration"><%= MP3Stat.to_mmss(song.duration) %></:col> <:col :let={%{song: song}} label="Duration"><%= MP3Stat.to_mmss(song.duration) %></:col>
<:col :let={%{song: song}} label="" if={@owns_profile?}> <:col :let={%{song: song}} label="" :if={@owns_profile?}>
<.link <.link
id={"delete-song-#{song.id}"} id={"delete-song-#{song.id}"}
phx-click={show_modal("delete-modal-#{song.id}")} phx-click={show_modal("delete-modal-#{song.id}")}
@ -109,6 +109,7 @@ defmodule LiveBeatsWeb.ProfileLive do
end end
def mount(%{"profile_username" => profile_username}, _session, socket) do def mount(%{"profile_username" => profile_username}, _session, socket) do
IO.inspect(get_connect_params(socket))
%{current_user: current_user} = socket.assigns %{current_user: current_user} = socket.assigns
profile = profile =

View file

@ -169,10 +169,10 @@ defmodule LiveBeatsWeb.ProfileLive.UploadFormComponent do
do: ~H|Something went wrong| do: ~H|Something went wrong|
defp file_error(%{kind: %Ecto.Changeset{}} = assigns), defp file_error(%{kind: %Ecto.Changeset{}} = assigns),
do: ~H|<%= @label %>: <%= LiveBeatsWeb.ErrorHelpers.translate_changeset_errors(@kind) %>| do: ~H|<%= @label %>: translate_changeset_errors(@kind) %>|
defp file_error(%{kind: {msg, opts}} = assigns) when is_binary(msg) and is_list(opts), defp file_error(%{kind: {msg, opts}} = assigns) when is_binary(msg) and is_list(opts),
do: ~H|<%= @label %>: <%= LiveBeatsWeb.ErrorHelpers.translate_error(@kind) %>| do: ~H|<%= @label %>: translate_error(@kind) %>|
defp put_stats(socket, entry_ref, %MP3Stat{} = stat) do defp put_stats(socket, entry_ref, %MP3Stat{} = stat) do
if changeset = get_changeset(socket, entry_ref) do if changeset = get_changeset(socket, entry_ref) do

View file

@ -64,7 +64,7 @@
<span phx-click={js_exec("##{@uploads.mp3.ref}", "click", [])}> <span phx-click={js_exec("##{@uploads.mp3.ref}", "click", [])}>
Upload files Upload files
</span> </span>
<%= live_file_input(@uploads.mp3, class: "sr-only", tabindex: "0") %> <.live_file_input upload={@uploads.mp3} class="sr-only" tabindex="0" />
</label> </label>
<p class="pl-1">or drag and drop</p> <p class="pl-1">or drag and drop</p>
</div> </div>

View file

@ -98,6 +98,7 @@ defmodule LiveBeatsWeb.SettingsLive do
end end
def mount(_params, _session, socket) do def mount(_params, _session, socket) do
IO.inspect(get_connect_params(socket))
changeset = Accounts.change_settings(socket.assigns.current_user, %{}) changeset = Accounts.change_settings(socket.assigns.current_user, %{})
{:ok, assign(socket, changeset: changeset)} {:ok, assign(socket, changeset: changeset)}
end end

View file

@ -8,7 +8,7 @@ defmodule LiveBeatsWeb.Router do
plug :accepts, ["html"] plug :accepts, ["html"]
plug :fetch_session plug :fetch_session
plug :fetch_live_flash plug :fetch_live_flash
plug :put_root_layout, {LiveBeatsWeb.LayoutView, :root} plug :put_root_layout, {LiveBeatsWeb.Layouts, :root}
plug :protect_from_forgery plug :protect_from_forgery
plug :put_secure_browser_headers plug :put_secure_browser_headers
end end

View file

@ -1,5 +0,0 @@
<main>
<p class="alert alert-info" role="alert"><%= get_flash(@conn, :info) %></p>
<p class="alert alert-danger" role="alert"><%= get_flash(@conn, :error) %></p>
<%= @inner_content %>
</main>

View file

@ -1,615 +0,0 @@
<!-- Pinned projects -->
<div class="px-4 mt-6 sm:px-6 lg:px-8">
<h2 class="text-gray-500 text-xs font-medium uppercase tracking-wide">Who's Here</h2>
<ul
role="list"
class="grid grid-cols-1 gap-4 sm:gap-6 sm:grid-cols-2 xl:grid-cols-4 mt-3"
x-max="1"
>
<li class="relative col-span-1 flex shadow-sm rounded-md">
<div class="flex-shrink-0 flex items-center justify-center w-16 bg-pink-600 text-white text-sm font-medium rounded-l-md">
CM
</div>
<div class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-md truncate">
<div class="flex-1 px-4 py-2 text-sm truncate">
<a href="#" class="text-gray-900 font-medium hover:text-gray-600">
Chris
</a>
<p class="text-gray-500">5 songs</p>
</div>
</div>
</li>
<li class="relative col-span-1 flex shadow-sm rounded-md">
<div class="flex-shrink-0 flex items-center justify-center w-16 bg-purple-600 text-white text-sm font-medium rounded-l-md">
KM
</div>
<div class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-md truncate">
<div class="flex-1 px-4 py-2 text-sm truncate">
<a href="#" class="text-gray-900 font-medium hover:text-gray-600">
Kurt
</a>
<p class="text-gray-500">1 song</p>
</div>
</div>
</li>
<li class="relative col-span-1 flex shadow-sm rounded-md">
<div class="flex-shrink-0 flex items-center justify-center w-16 bg-green-600 text-white text-sm font-medium rounded-l-md">
JV
</div>
<div class="flex-1 flex items-center justify-between border-t border-r border-b border-gray-200 bg-white rounded-r-md truncate">
<div class="flex-1 px-4 py-2 text-sm truncate">
<a href="#" class="text-gray-900 font-medium hover:text-gray-600">
José
</a>
<p class="text-gray-500">1 song</p>
</div>
</div>
</li>
</ul>
</div>
<!-- Projects list (only on smallest breakpoint) -->
<div class="mt-10 sm:hidden">
<div class="px-4 sm:px-6">
<h2 class="text-gray-500 text-xs font-medium uppercase tracking-wide">Projects</h2>
</div>
<ul role="list" class="mt-3 border-t border-gray-200 divide-y divide-gray-100">
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-pink-600" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
GraphQL API
<!-- space -->
<span class="truncate font-normal text-gray-500">in Engineering</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-purple-600" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
New Benefits Plan
<!-- space -->
<span class="truncate font-normal text-gray-500">in Human Resources</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-yellow-500" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
Onboarding Emails
<!-- space -->
<span class="truncate font-normal text-gray-500">in Customer Success</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-green-500" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
iOS App
<!-- space -->
<span class="truncate font-normal text-gray-500">in Engineering</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-pink-600" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
Marketing Site Redesign
<!-- space -->
<span class="truncate font-normal text-gray-500">in Engineering</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-purple-600" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
Hire CFO
<!-- space -->
<span class="truncate font-normal text-gray-500">in Human Resources</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-yellow-500" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
Android App
<!-- space -->
<span class="truncate font-normal text-gray-500">in Engineering</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-green-500" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
New Customer Portal
<!-- space -->
<span class="truncate font-normal text-gray-500">in Engineering</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-pink-600" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
Co-op Program
<!-- space -->
<span class="truncate font-normal text-gray-500">in Human Resources</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-purple-600" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
Implement NPS
<!-- space -->
<span class="truncate font-normal text-gray-500">in Customer Success</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-yellow-500" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
Employee Recognition Program
<!-- space -->
<span class="truncate font-normal text-gray-500">in Human Resources</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
<li>
<a
href="#"
class="group flex items-center justify-between px-4 py-4 hover:bg-gray-50 sm:px-6"
>
<span class="flex items-center truncate space-x-3">
<span class="w-2.5 h-2.5 flex-shrink-0 rounded-full bg-green-500" aria-hidden="true">
</span>
<span class="font-medium truncate text-sm leading-6">
Open Source Web Client
<!-- space -->
<span class="truncate font-normal text-gray-500">in Engineering</span>
</span>
</span>
<svg
class="ml-4 h-5 w-5 text-gray-400 group-hover:text-gray-500"
x-description="Heroicon name: solid/chevron-right"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd"
>
</path>
</svg>
</a>
</li>
</ul>
</div>
<!-- Songs table (small breakpoint and up) -->
<div class="hidden mt-8 sm:block">
<div class="align-middle inline-block min-w-full border-b border-gray-200">
<table class="min-w-full">
<thead>
<tr class="border-t border-gray-200">
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
<span class="lg:pl-2">Nextup</span>
</th>
<th class="px-6 py-3 border-b border-gray-200 bg-gray-50 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
likes
</th>
<th class="hidden md:table-cell px-6 py-3 border-b border-gray-200 bg-gray-50 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">
user
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-100">
<%= for _ <- 1..20 do %>
<tr>
<td class="px-6 py-3 max-w-0 w-full whitespace-nowrap text-sm font-medium text-gray-900">
<div class="flex items-center space-x-3 lg:pl-2">
<div class="flex-shrink-0 w-2.5 h-2.5 rounded-full bg-pink-600" aria-hidden="true">
</div>
<a href="#" class="truncate hover:text-gray-600">
<span>
GraphQL API
<!-- space -->
<span class="text-gray-500 font-normal">in Engineering</span>
</span>
</a>
</div>
</td>
<td class="px-6 py-3 text-sm text-gray-500 font-medium">
<div class="flex items-center space-x-2">
<div class="flex flex-shrink-0 -space-x-1">
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Dries Vincent"
/>
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1517841905240-472988babdf9?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Lindsay Walton"
/>
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Courtney Henry"
/>
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Tom Cook"
/>
</div>
<span class="flex-shrink-0 text-xs leading-5 font-medium">+8</span>
</div>
</td>
<td class="hidden md:table-cell px-6 py-3 whitespace-nowrap text-sm text-gray-500 text-right">
March 17, 2020
</td>
</tr>
<% end %>
<tr>
<td class="px-6 py-3 max-w-0 w-full whitespace-nowrap text-sm font-medium text-gray-900">
<div class="flex items-center space-x-3 lg:pl-2">
<div class="flex-shrink-0 w-2.5 h-2.5 rounded-full bg-purple-600" aria-hidden="true">
</div>
<a href="#" class="truncate hover:text-gray-600">
<span>
New Benefits Plan
<!-- space -->
<span class="text-gray-500 font-normal">in Human Resources</span>
</span>
</a>
</div>
</td>
<td class="px-6 py-3 text-sm text-gray-500 font-medium">
<div class="flex items-center space-x-2">
<div class="flex flex-shrink-0 -space-x-1">
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1519345182560-3f2917c472ef?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Leonard Krasner"
/>
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1463453091185-61582044d556?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Floyd Miles"
/>
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Emily Selman"
/>
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1500917293891-ef795e70e1f6?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Kristin Watson"
/>
</div>
<span class="flex-shrink-0 text-xs leading-5 font-medium">+4</span>
</div>
</td>
<td class="hidden md:table-cell px-6 py-3 whitespace-nowrap text-sm text-gray-500 text-right">
April 4, 2020
</td>
</tr>
<tr>
<td class="px-6 py-3 max-w-0 w-full whitespace-nowrap text-sm font-medium text-gray-900">
<div class="flex items-center space-x-3 lg:pl-2">
<div class="flex-shrink-0 w-2.5 h-2.5 rounded-full bg-yellow-500" aria-hidden="true">
</div>
<a href="#" class="truncate hover:text-gray-600">
<span>
Onboarding Emails
<!-- space -->
<span class="text-gray-500 font-normal">in Customer Success</span>
</span>
</a>
</div>
</td>
<td class="px-6 py-3 text-sm text-gray-500 font-medium">
<div class="flex items-center space-x-2">
<div class="flex flex-shrink-0 -space-x-1">
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1502685104226-ee32379fefbe?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Emily Selman"
/>
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1500917293891-ef795e70e1f6?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Kristin Watson"
/>
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1505840717430-882ce147ef2d?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Emma Dorsey"
/>
<img
class="max-w-none h-6 w-6 rounded-full ring-2 ring-white"
src="https://images.unsplash.com/photo-1509783236416-c9ad59bae472?ixlib=rb-1.2.1&amp;ixid=eyJhcHBfaWQiOjEyMDd9&amp;auto=format&amp;fit=facearea&amp;facepad=2&amp;w=256&amp;h=256&amp;q=80"
alt="Alicia Bell"
/>
</div>
<span class="flex-shrink-0 text-xs leading-5 font-medium">+10</span>
</div>
</td>
<td class="hidden md:table-cell px-6 py-3 whitespace-nowrap text-sm text-gray-500 text-right">
March 30, 2020
</td>
</tr>
</tbody>
</table>
</div>
</div>

View file

@ -1,74 +0,0 @@
defmodule LiveBeatsWeb.ErrorHelpers do
@moduledoc """
Conveniences for translating and building error messages.
"""
use Phoenix.HTML
import Phoenix.LiveView
import Phoenix.LiveView.Helpers
@doc """
Generates tag for inlined form input errors.
"""
def error_tag(form, field) do
error(%{errors: form.errors, field: field, input_name: input_name(form, field)})
end
def error(%{errors: errors, field: field} = assigns) do
assigns =
assigns
|> assign(:error_values, Keyword.get_values(errors, field))
|> assign_new(:class, fn -> "" end)
~H"""
<%= for error <- @error_values do %>
<span
phx-feedback-for={@input_name}
class={
"invalid-feedback inline-block pl-2 pr-2 text-sm text-white bg-red-600 rounded-md #{@class}"
}
>
<%= translate_error(error) %>
</span>
<% end %>
<%= if Enum.empty?(@error_values) do %>
<span class={"invalid-feedback inline-block h-0 #{@class}"}></span>
<% end %>
"""
end
@doc """
Translates an error message using gettext.
"""
def translate_error({msg, opts}) do
# When using gettext, we typically pass the strings we want
# to translate as a static argument:
#
# # Translate "is invalid" in the "errors" domain
# dgettext("errors", "is invalid")
#
# # Translate the number of files with plural rules
# dngettext("errors", "1 file", "%{count} files", count)
#
# Because the error messages we show in our forms and APIs
# are defined inside Ecto, we need to translate them dynamically.
# This requires us to call the Gettext module passing our gettext
# backend as first argument.
#
# Note we use the "errors" domain, which means translations
# should be written to the errors.po file. The :count option is
# set by Ecto and indicates we should also apply plural rules.
if count = opts[:count] do
Gettext.dngettext(LiveBeatsWeb.Gettext, "errors", msg, msg, count, opts)
else
Gettext.dgettext(LiveBeatsWeb.Gettext, "errors", msg, opts)
end
end
def translate_changeset_errors(changeset) do
changeset.errors
|> Enum.map(fn {key, value} -> "#{key} #{translate_error(value)}" end)
|> Enum.join("\n")
end
end

View file

@ -1,16 +0,0 @@
defmodule LiveBeatsWeb.ErrorView do
use LiveBeatsWeb, :view
# If you want to customize a particular status code
# for a certain format, you may uncomment below.
# def render("500.html", _assigns) do
# "Internal Server Error"
# end
# By default, Phoenix returns the status message from
# the template name. For example, "404.html" becomes
# "Not Found".
def template_not_found(template, _assigns) do
Phoenix.Controller.status_message_from_template(template)
end
end

View file

@ -1,3 +0,0 @@
defmodule LiveBeatsWeb.PageView do
use LiveBeatsWeb, :view
end

View file

@ -7,7 +7,6 @@ defmodule LiveBeats.MixProject do
version: "0.1.0", version: "0.1.0",
elixir: "~> 1.12", elixir: "~> 1.12",
elixirc_paths: elixirc_paths(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()),
compilers: [:gettext, :phoenix_live_view] ++ Mix.compilers(),
start_permanent: Mix.env() == :prod, start_permanent: Mix.env() == :prod,
aliases: aliases(), aliases: aliases(),
deps: deps() deps: deps()
@ -33,18 +32,19 @@ defmodule LiveBeats.MixProject do
# Type `mix help deps` for examples and options. # Type `mix help deps` for examples and options.
defp deps do defp deps do
[ [
{:phoenix, github: "phoenixframework/phoenix", override: true}, {:phoenix, "~> 1.7.0-rc.0", override: true},
{:phoenix_live_view, "~> 0.18.3"},
{:phoenix_live_dashboard, "~> 0.7.2"},
{:phoenix_ecto, "~> 4.4"}, {:phoenix_ecto, "~> 4.4"},
{:ecto_sql, "~> 3.6"}, {:ecto_sql, "~> 3.6"},
{:ecto_network, "~> 1.3.0"}, {:ecto_network, "~> 1.3.0"},
{:postgrex, ">= 0.0.0"}, {:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 3.0"}, {:phoenix_html, "~> 3.0"},
{:phoenix_live_reload, "~> 1.2", only: :dev}, {:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, github: "phoenixframework/phoenix_live_view", override: true},
{:floki, ">= 0.30.0", only: :test}, {:floki, ">= 0.30.0", only: :test},
{:phoenix_live_dashboard, "~> 0.6"},
{:esbuild, "~> 0.2", runtime: Mix.env() == :dev}, {:esbuild, "~> 0.2", runtime: Mix.env() == :dev},
{:swoosh, "~> 1.3"}, {:swoosh, "~> 1.3"},
{:finch, "~> 0.13"},
{:telemetry_metrics, "~> 0.6"}, {:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"}, {:telemetry_poller, "~> 1.0"},
{:gettext, "~> 0.18"}, {:gettext, "~> 0.18"},

View file

@ -1,46 +1,45 @@
%{ %{
"castore": {:hex, :castore, "0.1.13", "ccf3ab251ffaebc4319f41d788ce59a6ab3f42b6c27e598ad838ffecee0b04f9", [:mix], [], "hexpm", "a14a7eecfec7e20385493dbb92b0d12c5d77ecfd6307de10102d58c94e8c49c0"}, "castore": {:hex, :castore, "0.1.19", "a2c3e46d62b7f3aa2e6f88541c21d7400381e53704394462b9fd4f06f6d42bb6", [:mix], [], "hexpm", "e96e0161a5dc82ef441da24d5fa74aefc40d920f3a6645d15e1f9f3e66bb2109"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"}, "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"db_connection": {:hex, :db_connection, "2.4.0", "d04b1b73795dae60cead94189f1b8a51cc9e1f911c234cc23074017c43c031e5", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "ad416c21ad9f61b3103d254a71b63696ecadb6a917b36f563921e0de00d7d7c8"}, "db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"ecto": {:hex, :ecto, "3.7.1", "a20598862351b29f80f285b21ec5297da1181c0442687f9b8329f0445d228892", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d36e5b39fc479e654cffd4dbe1865d9716e4a9b6311faff799b6f90ab81b8638"}, "ecto": {:hex, :ecto, "3.9.1", "67173b1687afeb68ce805ee7420b4261649d5e2deed8fe5550df23bab0bc4396", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c80bb3d736648df790f7f92f81b36c922d9dd3203ca65be4ff01d067f54eb304"},
"ecto_network": {:hex, :ecto_network, "1.3.0", "1e77fa37c20e0f6a426d3862732f3317b0fa4c18f123d325f81752a491d7304e", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "053a5e46ef2837e8ea5ea97c82fa0f5494699209eddd764e663c85f11b2865bd"}, "ecto_network": {:hex, :ecto_network, "1.3.0", "1e77fa37c20e0f6a426d3862732f3317b0fa4c18f123d325f81752a491d7304e", [:mix], [{:ecto_sql, ">= 3.0.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:phoenix_html, ">= 0.0.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:postgrex, ">= 0.14.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "053a5e46ef2837e8ea5ea97c82fa0f5494699209eddd764e663c85f11b2865bd"},
"ecto_sql": {:hex, :ecto_sql, "3.7.0", "2fcaad4ab0c8d76a5afbef078162806adbe709c04160aca58400d5cbbe8eeac6", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a26135dfa1d99bf87a928c464cfa25bba6535a4fe761eefa56077a4febc60f70"}, "ecto_sql": {:hex, :ecto_sql, "3.9.0", "2bb21210a2a13317e098a420a8c1cc58b0c3421ab8e3acfa96417dab7817918c", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.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", "a8f3f720073b8b1ac4c978be25fa7960ed7fd44997420c304a4a2e200b596453"},
"erlog": {:git, "git://github.com/segun/erlog.git", "76825e0500b6b62b99f28411933dc15a1cb2817f", [ref: "master"]}, "esbuild": {:hex, :esbuild, "0.5.0", "d5bb08ff049d7880ee3609ed5c4b864bd2f46445ea40b16b4acead724fb4c4a3", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "f183a0b332d963c4cfaf585477695ea59eef9a6f2204fdd0efa00e099694ffe5"},
"erlp3tags": {:git, "https://github.com/segun/erlp3tags.git", "9b6c72da9057b9e00c7711148ce10e6cdbacae18", []},
"esbuild": {:hex, :esbuild, "0.3.4", "416203c642eb84b207f882cf7953a1fd7bb71e23f5f86554f983bb7bad18b897", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "c472e38b37e9547113776b1e4b64b44ec540bcc7056dd252c2c3ffba41aa9793"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"floki": {:hex, :floki, "0.31.0", "f05ee8a8e6a3ced4e62beeb2c79a63bc8e12ab98fbaaf6e6a3d9b76b1278e23f", [:mix], [{:html_entities, "~> 0.5.0", [hex: :html_entities, repo: "hexpm", optional: false]}], "hexpm", "b05afa372f5c345a5bf240ac25ea1f0f3d5fcfd7490ac0beeb4a203f9444891e"}, "finch": {:hex, :finch, "0.13.0", "c881e5460ec563bf02d4f4584079e62201db676ed4c0ef3e59189331c4eddf7b", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "49957dcde10dcdc042a123a507a9c5ec5a803f53646d451db2f7dea696fba6cc"},
"gettext": {:hex, :gettext, "0.18.2", "7df3ea191bb56c0309c00a783334b288d08a879f53a7014341284635850a6e55", [:mix], [], "hexpm", "f9f537b13d4fdd30f3039d33cb80144c3aa1f8d9698e47d7bcbcc8df93b1f5c5"}, "floki": {:hex, :floki, "0.34.0", "002d0cc194b48794d74711731db004fafeb328fe676976f160685262d43706a8", [:mix], [], "hexpm", "9c3a9f43f40dde00332a589bd9d389b90c1f518aef500364d00636acc5ebc99c"},
"gettext": {:hex, :gettext, "0.20.0", "75ad71de05f2ef56991dbae224d35c68b098dd0e26918def5bb45591d5c8d429", [:mix], [], "hexpm", "1c03b177435e93a47441d7f681a7040bd2a816ece9e2666d1c9001035121eb3d"},
"heroicons": {:hex, :heroicons, "0.2.4", "12824795f25340415bffa9a501b96c89dc856ed732e82acccdab635fee92411b", [:mix], [{:phoenix_html, "~> 2.14 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "7d6c51dc8ecaadb37943247da83ec2fbf3f6b479a23f4cf0195bd61ec2268128"}, "heroicons": {:hex, :heroicons, "0.2.4", "12824795f25340415bffa9a501b96c89dc856ed732e82acccdab635fee92411b", [:mix], [{:phoenix_html, "~> 2.14 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}], "hexpm", "7d6c51dc8ecaadb37943247da83ec2fbf3f6b479a23f4cf0195bd61ec2268128"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"id3": {:hex, :id3, "1.0.1", "344840dee445c19be4b6dca9c70f0a7cd5dd03cb4260bae8ad9a21457ef12813", [:mix], [{:rustler, "~> 0.21.0", [hex: :rustler, repo: "hexpm", optional: false]}], "hexpm", "07ee2a284414065920751a528f237e77dc2aeed222a75302f909f3c07fd867e1"}, "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
"jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"},
"libcluster": {:hex, :libcluster, "3.3.1", "e7a4875cd1290cee7a693d6bd46076863e9e433708b01339783de6eff5b7f0aa", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b575ca63c1cd84e01f3fa0fc45e6eb945c1ee7ae8d441d33def999075e9e5398"}, "libcluster": {:hex, :libcluster, "3.3.1", "e7a4875cd1290cee7a693d6bd46076863e9e433708b01339783de6eff5b7f0aa", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "b575ca63c1cd84e01f3fa0fc45e6eb945c1ee7ae8d441d33def999075e9e5398"},
"mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"}, "mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"},
"mint": {:hex, :mint, "1.3.0", "396b3301102f7b775e103da5a20494b25753aed818d6d6f0ad222a3a018c3600", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "a9aac960562e43ca69a77e5176576abfa78b8398cec5543dd4fb4ab0131d5c1e"}, "mint": {:hex, :mint, "1.4.2", "50330223429a6e1260b2ca5415f69b0ab086141bc76dc2fbf34d7c389a6675b2", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "ce75a5bbcc59b4d7d8d70f8b2fc284b1751ffb35c7b6a6302b5192f8ab4ddd80"},
"phoenix": {:git, "https://github.com/phoenixframework/phoenix.git", "063bb8c37b05a61b6f411ef4b678efe0cd4e3841", []}, "nimble_options": {:hex, :nimble_options, "0.4.0", "c89babbab52221a24b8d1ff9e7d838be70f0d871be823165c94dd3418eea728f", [:mix], [], "hexpm", "e6701c1af326a11eea9634a3b1c62b475339ace9456c1a23ec3bc9a847bca02d"},
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"phoenix": {:hex, :phoenix, "1.7.0-rc.0", "8e328572f496b5170e879da94baa57c5f878f354d50eac052c9a7c6d57c2cf54", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "ed503f6c55184afc0a453e44e6ab2a09f014f59b7fdd682313fdc52ec2f82859"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
"phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"}, "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.2", "0769470265eb13af01b5001b29cb935f4710d6adaa1ffc18417a570a337a2f0f", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.1", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "5bc6c6b38a2ca8b5020b442322fcee6afd5e641637a0b1fb059d4bd89bc58e7b"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.3.3", "3a53772a6118d5679bf50fc1670505a290e32a1d195df9e069d8c53ab040c054", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "766796676e5f558dbae5d1bdb066849673e956005e3730dfd5affd7a6da4abac"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.0", "4fe222c0be55fdc3f9c711e24955fc42a7cd9b7a2f5f406f2580a567c335a573", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "bebf0fc2d2113b61cb5968f585367234b7b4c21d963d691de7b4b2dc6cdaae6f"},
"phoenix_live_view": {:git, "https://github.com/phoenixframework/phoenix_live_view.git", "aab28ef96bf79a4218c1402a4aef6c3613380e1a", []}, "phoenix_live_view": {:hex, :phoenix_live_view, "0.18.3", "2e3d009422addf8b15c3dccc65ce53baccbe26f7cfd21d264680b5867789a9c1", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c8845177a866e017dcb7083365393c8f00ab061b8b6b2bda575891079dce81b2"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
"phoenix_view": {:hex, :phoenix_view, "1.0.0", "fea71ecaaed71178b26dd65c401607de5ec22e2e9ef141389c721b3f3d4d8011", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "82be3e2516f5633220246e2e58181282c71640dab7afc04f70ad94253025db0c"}, "phoenix_template": {:hex, :phoenix_template, "1.0.0", "c57bc5044f25f007dc86ab21895688c098a9f846a8dda6bc40e2d0ddc146e38f", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "1b066f99a26fd22064c12b2600a9a6e56700f591bf7b20b418054ea38b4d4357"},
"plug": {:hex, :plug, "1.13.4", "addb6e125347226e3b11489e23d22a60f7ab74786befb86c14f94fb5f23ca9a4", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "06114c1f2a334212fe3ae567dbb3b1d29fd492c1a09783d52f3d489c1a6f4cf2"}, "plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"},
"plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"}, "plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"},
"plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"}, "plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"},
"porcelain": {:hex, :porcelain, "2.0.3", "2d77b17d1f21fed875b8c5ecba72a01533db2013bd2e5e62c6d286c029150fdc", [:mix], [], "hexpm", "dc996ab8fadbc09912c787c7ab8673065e50ea1a6245177b0c24569013d23620"}, "postgrex": {:hex, :postgrex, "0.16.5", "fcc4035cc90e23933c5d69a9cd686e329469446ef7abba2cf70f08e2c4b69810", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "edead639dc6e882618c01d8fc891214c481ab9a3788dfe38dd5e37fd1d5fb2e8"},
"postgrex": {:hex, :postgrex, "0.15.10", "2809dee1b1d76f7cbabe570b2a9285c2e7b41be60cf792f5f2804a54b838a067", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "1560ca427542f6b213f8e281633ae1a3b31cdbcd84ebd7f50628765b8f6132be"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"rustler": {:hex, :rustler, "0.22.2", "f92d6dba71bef6fe5f0d955649cb071127adc92f32a78890e8fa9939e59a1b41", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: false]}, {:toml, "~> 0.5.2", [hex: :toml, repo: "hexpm", optional: false]}], "hexpm", "56b129141e86d60a2d670af9a2b55a9071e10933ef593034565af77e84655118"}, "swoosh": {:hex, :swoosh, "1.8.2", "af9a22ab2c0d20b266f61acca737fa11a121902de9466a39e91bacdce012101c", [: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_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d058ba750eafadb6c09a84a352c14c5d1eeeda6e84945fcc95785b7f3067b7db"},
"swoosh": {:hex, :swoosh, "1.5.0", "2be4cfc1be10f2203d1854c85b18d8c7be0321445a782efd53ef0b2b88f03ce4", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, 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_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b53891359e3ddca263ece784051243de84c9244c421a0dee1bff1d52fc5ca420"}, "tailwind": {:hex, :tailwind, "0.1.9", "25ba09d42f7bfabe170eb67683a76d6ec2061952dc9bd263a52a99ba3d24bd4d", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "9213f87709c458aaec313bb5f2df2b4d2cedc2b630e4ae821bf3c54c47a56d0b"},
"tailwind": {:hex, :tailwind, "0.1.3", "117ada41ee06343d77269ee5f5ef58ef93ddf4d596a0486db7be9d6157487f9e", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "1fe9ecb50ae521a328a787f22b60fb0e14d29c8d2a5983186962fdbd8162608a"}, "telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"},
"telemetry": {:hex, :telemetry, "1.0.0", "0f453a102cdf13d506b7c0ab158324c337c41f1cc7548f0bc0e130bbf0ae9452", [:rebar3], [], "hexpm", "73bc09fa59b4a0284efb4624335583c528e07ec9ae76aca96ea0673850aec57a"},
"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_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_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"toml": {:hex, :toml, "0.5.2", "e471388a8726d1ce51a6b32f864b8228a1eb8edc907a0edf2bb50eab9321b526", [:mix], [], "hexpm", "f1e3dabef71fb510d015fad18c0e05e7c57281001141504c6b69d94e99750a07"}, "websock": {:hex, :websock, "0.4.3", "184ac396bdcd3dfceb5b74c17d221af659dd559a95b1b92041ecb51c9b728093", [:mix], [], "hexpm", "5e4dd85f305f43fd3d3e25d70bec4a45228dfed60f0f3b072d8eddff335539cf"},
"websock_adapter": {:hex, :websock_adapter, "0.4.5", "30038a3715067f51a9580562c05a3a8d501126030336ffc6edb53bf57d6d2d26", [:mix], [{:bandit, "~> 0.6", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.4", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "1d9812dc7e703c205049426fd4fe0852a247a825f91b099e53dc96f68bafe4c8"},
} }

View file

@ -5,7 +5,7 @@ defmodule LiveBeatsWeb.ProfileLiveTest do
import LiveBeats.AccountsFixtures import LiveBeats.AccountsFixtures
alias LiveBeats.MediaLibrary alias LiveBeats.MediaLibrary
alias LiveBeatsWeb.LiveHelpers alias LiveBeatsWeb.CoreComponents
setup %{conn: conn} do setup %{conn: conn} do
current_user = user_fixture(%{username: "chrismccord"}) current_user = user_fixture(%{username: "chrismccord"})
@ -17,7 +17,7 @@ defmodule LiveBeatsWeb.ProfileLiveTest do
describe "own profile" do describe "own profile" do
test "profile page uploads", %{conn: conn, current_user: current_user} do test "profile page uploads", %{conn: conn, current_user: current_user} do
profile = MediaLibrary.get_profile!(current_user) profile = MediaLibrary.get_profile!(current_user)
{:ok, lv, dead_html} = live(conn, LiveHelpers.profile_path(current_user)) {:ok, lv, dead_html} = live(conn, CoreComponents.profile_path(current_user))
assert dead_html =~ "chrismccord&#39;s beats" assert dead_html =~ "chrismccord&#39;s beats"
@ -59,7 +59,7 @@ defmodule LiveBeatsWeb.ProfileLiveTest do
song = MediaLibrary.get_first_song(profile) song = MediaLibrary.get_first_song(profile)
assert lv |> element("#delete-modal-#{song.id}-confirm") |> render_click() assert lv |> element("#delete-modal-#{song.id}-confirm") |> render_click()
{:ok, refreshed_lv, _} = live(conn, LiveHelpers.profile_path(current_user)) {:ok, refreshed_lv, _} = live(conn, CoreComponents.profile_path(current_user))
refute render(refreshed_lv) =~ "silence1s" refute render(refreshed_lv) =~ "silence1s"
end end