From 0334260de547383987c058e9160172b20e4853c4 Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 9 Jul 2025 20:04:26 +0200 Subject: [PATCH] feat: migration to phoenix 1.8 - merge changed files --- assets/css/app.css | 1 - config/config.exs | 13 +- config/dev.exs | 12 +- config/runtime.exs | 2 +- lib/mv/application.ex | 2 - lib/mv_web.ex | 13 +- lib/mv_web/components/core_components.ex | 539 ++++++------------- lib/mv_web/components/layouts.ex | 9 + lib/mv_web/components/layouts/app.html.heex | 39 -- lib/mv_web/components/layouts/root.html.heex | 26 +- lib/mv_web/endpoint.ex | 7 +- mix.exs | 19 +- mix.lock | 4 +- 13 files changed, 233 insertions(+), 453 deletions(-) delete mode 100644 lib/mv_web/components/layouts/app.html.heex diff --git a/assets/css/app.css b/assets/css/app.css index 1abadc7..0417463 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -5,7 +5,6 @@ @source "../css"; @source "../js"; @source "../../lib/mv_web"; -@source "../../deps/ash_authentication_phoenix"; /* A Tailwind plugin that makes "hero-#{ICON}" classes available. The heroicons installation itself is managed by your mix.exs */ diff --git a/config/config.exs b/config/config.exs index 43c8cf8..29a4211 100644 --- a/config/config.exs +++ b/config/config.exs @@ -76,25 +76,24 @@ config :esbuild, version: "0.17.11", mv: [ args: - ~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*), + ~w(js/app.js --bundle --target=es2022 --outdir=../priv/static/assets/js --external:/fonts/* --external:/images/*), cd: Path.expand("../assets", __DIR__), env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)} ] # Configure tailwind (the version is required) config :tailwind, - version: "3.4.3", + version: "4.0.9", mv: [ args: ~w( - --config=tailwind.config.js - --input=css/app.css - --output=../priv/static/assets/app.css + --input=assets/css/app.css + --output=priv/static/assets/css/app.css ), - cd: Path.expand("../assets", __DIR__) + cd: Path.expand("..", __DIR__) ] # Configures Elixir's Logger -config :logger, :console, +config :logger, :default_formatter, format: "$time $metadata[$level] $message\n", metadata: [:request_id] diff --git a/config/dev.exs b/config/dev.exs index 17b4ce1..51ed2f1 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -17,10 +17,10 @@ config :mv, Mv.Repo, # The watchers configuration can be used to run external # watchers to your application. For example, we can use it # to bundle .js and .css sources. -# Binding to loopback ipv4 address prevents access from other machines. config :mv, MvWeb.Endpoint, + # Binding to loopback ipv4 address prevents access from other machines. # Change to `ip: {0, 0, 0, 0}` to allow access from other machines. - http: [ip: {127, 0, 0, 1}, port: 4000], + http: [ip: {127, 0, 0, 1}, port: String.to_integer(System.get_env("PORT") || "4000")], check_origin: false, code_reloader: true, debug_errors: true, @@ -56,10 +56,11 @@ config :mv, MvWeb.Endpoint, # Watch static and templates for browser reloading. config :mv, MvWeb.Endpoint, live_reload: [ + web_console_logger: true, patterns: [ ~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$", ~r"priv/gettext/.*(po)$", - ~r"lib/mv_web/(controllers|live|components)/.*(ex|heex)$" + ~r"lib/mv_web/(?:controllers|live|components|router)/?.*\.(ex|heex)$" ] ] @@ -67,7 +68,7 @@ config :mv, MvWeb.Endpoint, config :mv, dev_routes: true # Do not include metadata nor timestamps in development logs -config :logger, :console, format: "[$level] $message\n" +config :logger, :default_formatter, format: "[$level] $message\n" # Set a higher stacktrace during development. Avoid configuring such # in production as building large stacktraces may be expensive. @@ -77,7 +78,8 @@ config :phoenix, :stacktrace_depth, 20 config :phoenix, :plug_init_mode, :runtime config :phoenix_live_view, - # Include HEEx debug annotations as HTML comments in rendered markup + # Include HEEx debug annotations as HTML comments in rendered markup. + # Changing this configuration will require mix clean and a full recompile. debug_heex_annotations: true, # Enable helpful, but potentially expensive runtime checks enable_expensive_runtime_checks: true diff --git a/config/runtime.exs b/config/runtime.exs index e8ab249..464d8cd 100644 --- a/config/runtime.exs +++ b/config/runtime.exs @@ -116,7 +116,7 @@ if config_env() == :prod do # domain: System.get_env("MAILGUN_DOMAIN") # # For this example you need include a HTTP client required by Swoosh API client. - # Swoosh supports Hackney and Finch out of the box: + # Swoosh supports Hackney, Req and Finch out of the box: # # config :swoosh, :api_client, Swoosh.ApiClient.Hackney # diff --git a/lib/mv/application.ex b/lib/mv/application.ex index e0bf462..b77107e 100644 --- a/lib/mv/application.ex +++ b/lib/mv/application.ex @@ -12,8 +12,6 @@ defmodule Mv.Application do Mv.Repo, {DNSCluster, query: Application.get_env(:mv, :dns_cluster_query) || :ignore}, {Phoenix.PubSub, name: Mv.PubSub}, - # Start the Finch HTTP client for sending emails - {Finch, name: Mv.Finch}, {AshAuthentication.Supervisor, otp_app: :my}, # Start a worker by calling: Mv.Worker.start_link(arg) # {Mv.Worker, arg}, diff --git a/lib/mv_web.ex b/lib/mv_web.ex index 4254449..f743377 100644 --- a/lib/mv_web.ex +++ b/lib/mv_web.ex @@ -38,9 +38,7 @@ defmodule MvWeb do def controller do quote do - use Phoenix.Controller, - formats: [:html, :json], - layouts: [html: MvWeb.Layouts] + use Phoenix.Controller, formats: [:html, :json] use Gettext, backend: MvWeb.Gettext @@ -52,10 +50,10 @@ defmodule MvWeb do def live_view do quote do - use Phoenix.LiveView, - layout: {MvWeb.Layouts, :app} - + use Phoenix.LiveView + on_mount MvWeb.LiveHelpers + unquote(html_helpers()) end end @@ -91,8 +89,9 @@ defmodule MvWeb do # Core UI components import MvWeb.CoreComponents - # Shortcut for generating JS commands + # Common modules used in templates alias Phoenix.LiveView.JS + alias MvWeb.Layouts # Routes generation with the ~p sigil unquote(verified_routes()) diff --git a/lib/mv_web/components/core_components.ex b/lib/mv_web/components/core_components.ex index c35f1ce..656d3c0 100644 --- a/lib/mv_web/components/core_components.ex +++ b/lib/mv_web/components/core_components.ex @@ -3,92 +3,34 @@ defmodule MvWeb.CoreComponents do Provides core UI components. At first glance, this module may seem daunting, but its goal is to provide - core building blocks for your application, such as modals, tables, and - forms. The components consist mostly of markup and are well-documented + core building blocks for your application, such as tables, forms, and + inputs. The components consist mostly of markup and are well-documented with doc strings and declarative assigns. You may customize and style them in any way you want, based on your application growth and needs. - The default components use Tailwind CSS, a utility-first CSS framework. - See the [Tailwind CSS documentation](https://tailwindcss.com) to learn - how to customize them or feel free to swap in another framework altogether. + The foundation for styling is Tailwind CSS, a utility-first CSS framework, + augmented with daisyUI, a Tailwind CSS plugin that provides UI components + and themes. Here are useful references: + + * [daisyUI](https://daisyui.com/docs/intro/) - a good place to get + started and see the available components. + + * [Tailwind CSS](https://tailwindcss.com) - the foundational framework + we build on. You will use it for layout, sizing, flexbox, grid, and + spacing. + + * [Heroicons](https://heroicons.com) - see `icon/1` for usage. + + * [Phoenix.Component](https://hexdocs.pm/phoenix_live_view/Phoenix.Component.html) - + the component system used by Phoenix. Some components, such as `<.link>` + and `<.form>`, are defined there. - Icons are provided by [heroicons](https://heroicons.com). See `icon/1` for usage. """ use Phoenix.Component use Gettext, backend: MvWeb.Gettext alias Phoenix.LiveView.JS - @doc """ - Renders a modal. - - ## Examples - - <.modal id="confirm-modal"> - This is a modal. - - - JS commands may be passed to the `:on_cancel` to configure - the closing/cancel event, for example: - - <.modal id="confirm" on_cancel={JS.navigate(~p"/posts")}> - This is another modal. - - - """ - attr :id, :string, required: true - attr :show, :boolean, default: false - attr :on_cancel, JS, default: %JS{} - slot :inner_block, required: true - - def modal(assigns) do - ~H""" - - """ - end - - @doc """ - Shows the flash group with standard titles and content. - - ## Examples - - <.flash_group flash={@flash} /> - """ - attr :flash, :map, required: true, doc: "the map of flash messages" - attr :id, :string, default: "flash-group", doc: "the optional id of flash container" - - def flash_group(assigns) do - ~H""" -
- <.flash kind={:info} title={gettext("Success!")} flash={@flash} /> - <.flash kind={:error} title={gettext("Error!")} flash={@flash} /> - <.flash - id="client-error" - kind={:error} - title={gettext("We can't find the internet")} - phx-disconnected={show(".phx-client-error #client-error")} - phx-connected={hide("#client-error")} - hidden - > - {gettext("Attempting to reconnect")} - <.icon name="hero-arrow-path" class="ml-1 h-3 w-3 animate-spin" /> - - - <.flash - id="server-error" - kind={:error} - title={gettext("Something went wrong!")} - phx-disconnected={show(".phx-server-error #server-error")} - phx-connected={hide("#server-error")} - hidden - > - {gettext("Hang in there while we get back on track")} - <.icon name="hero-arrow-path" class="ml-1 h-3 w-3 animate-spin" /> - -
- """ - end - - @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 - - - """ - attr :for, :any, required: true, doc: "the data structure 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 multipart), - 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}> -
- {render_slot(@inner_block, f)} -
- {render_slot(action, f)} +
+ <.icon :if={@kind == :info} name="hero-information-circle" class="size-5 shrink-0" /> + <.icon :if={@kind == :error} name="hero-exclamation-circle" class="size-5 shrink-0" /> +
+

{@title}

+

{msg}

+
+
- +
""" end @doc """ - Renders a button. + Renders a button with navigation support. ## Examples <.button>Send! - <.button phx-click="go" class="ml-2">Send! + <.button phx-click="go" variant="primary">Send! + <.button navigate={~p"/"}>Home """ - attr :type, :string, default: nil - attr :class, :string, default: nil - attr :rest, :global, include: ~w(disabled form name value) - + attr :rest, :global, include: ~w(href navigate patch method) + attr :variant, :string, values: ~w(primary) slot :inner_block, required: true - def button(assigns) do - ~H""" - - """ + def button(%{rest: rest} = assigns) do + variants = %{"primary" => "btn-primary", nil => "btn-primary btn-soft"} + assigns = assign(assigns, :class, Map.fetch!(variants, assigns[:variant])) + + if rest[:href] || rest[:navigate] || rest[:patch] do + ~H""" + <.link class={["btn", @class]} {@rest}> + {render_slot(@inner_block)} + + """ + else + ~H""" + + """ + end end @doc """ @@ -276,7 +145,7 @@ defmodule MvWeb.CoreComponents do attr :type, :string, default: "text", values: ~w(checkbox color date datetime-local email file month number password - range search select tel text textarea time url week) + search select tel text textarea time url week) attr :field, Phoenix.HTML.FormField, doc: "a form field struct retrieved from the form, for example: @form[:email]" @@ -286,6 +155,8 @@ defmodule MvWeb.CoreComponents do attr :prompt, :string, default: nil, doc: "the prompt for select inputs" attr :options, :list, doc: "the options to pass to Phoenix.HTML.Form.options_for_select/2" attr :multiple, :boolean, default: false, doc: "the multiple flag for select inputs" + attr :class, :string, default: nil, doc: "the input class to use over defaults" + attr :error_class, :string, default: nil, doc: "the input error class to use over defaults" attr :rest, :global, include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength @@ -309,108 +180,95 @@ defmodule MvWeb.CoreComponents do end) ~H""" -
-
+ """ end def input(%{type: "select"} = assigns) do ~H""" -
- <.label for={@id}>{@label} - +
+ <.error :for={msg <- @errors}>{msg} -
+ """ end def input(%{type: "textarea"} = assigns) do ~H""" -
- <.label for={@id}>{@label} - +
+ <.error :for={msg <- @errors}>{msg} -
+ """ end # All other inputs text, datetime-local, url, password, etc. are handled here... def input(assigns) do ~H""" -
- <.label for={@id}>{@label} - +
+ <.error :for={msg <- @errors}>{msg} -
+ """ end - @doc """ - Renders a label. - """ - attr :for, :string, default: nil - slot :inner_block, required: true - - def label(assigns) do + # Helper used by inputs to generate form errors + defp error(assigns) do ~H""" - - """ - end - - @doc """ - Generates a generic error message. - """ - slot :inner_block, required: true - - def error(assigns) do - ~H""" -

- <.icon name="hero-exclamation-circle-mini" class="mt-0.5 h-5 w-5 flex-none" /> +

+ <.icon name="hero-exclamation-circle" class="size-5" /> {render_slot(@inner_block)}

""" @@ -427,12 +285,12 @@ defmodule MvWeb.CoreComponents do def header(assigns) do ~H""" -
+
-

+

{render_slot(@inner_block)}

-

+

{render_slot(@subtitle)}

@@ -473,49 +331,34 @@ defmodule MvWeb.CoreComponents do end ~H""" -
- - - - - - - - - - - - - -
{col[:label]} - {gettext("Actions")} -
-
- - - {render_slot(col, @row_item.(row))} - -
-
-
- - - {render_slot(action, @row_item.(row))} - -
-
-
+ + + + + + + + + + + + + +
{col[:label]} + {gettext("Actions")} +
+ {render_slot(col, @row_item.(row))} + +
+ <%= for action <- @action do %> + {render_slot(action, @row_item.(row))} + <% end %> +
+
""" end @@ -535,38 +378,14 @@ defmodule MvWeb.CoreComponents do def list(assigns) do ~H""" -
-
-
-
{item.title}
-
{render_slot(item)}
+
    +
  • +
    +
    {item.title}
    +
    {render_slot(item)}
    -
-
- """ - end - - @doc """ - Renders a back navigation link. - - ## Examples - - <.back navigate={~p"/posts"}>Back to posts - """ - attr :navigate, :any, required: true - slot :inner_block, required: true - - def back(assigns) do - ~H""" -
- <.link - navigate={@navigate} - class="text-sm font-semibold leading-6 text-zinc-900 hover:text-zinc-700" - > - <.icon name="hero-arrow-left-solid" class="h-3 w-3" /> - {render_slot(@inner_block)} - -
+ + """ end @@ -581,15 +400,15 @@ defmodule MvWeb.CoreComponents do width, height, and background color classes. Icons are extracted from the `deps/heroicons` directory and bundled within - your compiled app.css by the plugin in your `assets/tailwind.config.js`. + your compiled app.css by the plugin in `assets/vendor/heroicons.js`. ## Examples - <.icon name="hero-x-mark-solid" /> - <.icon name="hero-arrow-path" class="ml-1 w-3 h-3 animate-spin" /> + <.icon name="hero-x-mark" /> + <.icon name="hero-arrow-path" class="ml-1 size-3 motion-safe:animate-spin" /> """ attr :name, :string, required: true - attr :class, :string, default: nil + attr :class, :string, default: "size-4" def icon(%{name: "hero-" <> _} = assigns) do ~H""" @@ -604,7 +423,7 @@ defmodule MvWeb.CoreComponents do to: selector, time: 300, transition: - {"transition-all transform ease-out duration-300", + {"transition-all ease-out duration-300", "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95", "opacity-100 translate-y-0 sm:scale-100"} ) @@ -615,37 +434,11 @@ defmodule MvWeb.CoreComponents do to: selector, time: 200, transition: - {"transition-all transform ease-in duration-200", - "opacity-100 translate-y-0 sm:scale-100", + {"transition-all ease-in duration-200", "opacity-100 translate-y-0 sm:scale-100", "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"} ) end - def show_modal(js \\ %JS{}, id) when is_binary(id) do - js - |> JS.show(to: "##{id}") - |> JS.show( - to: "##{id}-bg", - time: 300, - transition: {"transition-all transform ease-out duration-300", "opacity-0", "opacity-100"} - ) - |> show("##{id}-container") - |> JS.add_class("overflow-hidden", to: "body") - |> JS.focus_first(to: "##{id}-content") - end - - def hide_modal(js \\ %JS{}, id) do - js - |> JS.hide( - to: "##{id}-bg", - transition: {"transition-all transform ease-in duration-200", "opacity-100", "opacity-0"} - ) - |> hide("##{id}-container") - |> JS.hide(to: "##{id}", transition: {"block", "block", "hidden"}) - |> JS.remove_class("overflow-hidden", to: "body") - |> JS.pop_focus() - end - @doc """ Translates an error message using gettext. """ diff --git a/lib/mv_web/components/layouts.ex b/lib/mv_web/components/layouts.ex index 1ced765..ba8ec67 100644 --- a/lib/mv_web/components/layouts.ex +++ b/lib/mv_web/components/layouts.ex @@ -40,6 +40,15 @@ defmodule MvWeb.Layouts do
    +
  • +
    + + +
    +
  • Website
  • diff --git a/lib/mv_web/components/layouts/app.html.heex b/lib/mv_web/components/layouts/app.html.heex deleted file mode 100644 index 54258db..0000000 --- a/lib/mv_web/components/layouts/app.html.heex +++ /dev/null @@ -1,39 +0,0 @@ -
    -
    -
    - - - -

    - v{Application.spec(:phoenix, :vsn)} -

    -
    -
    -
    - - -
    - - @elixirphoenix - - - GitHub - - - Get Started - -
    -
    -
    -
    -
    - <.flash_group flash={@flash} /> - {@inner_content} -
    -
    diff --git a/lib/mv_web/components/layouts/root.html.heex b/lib/mv_web/components/layouts/root.html.heex index 9857506..5ee0fef 100644 --- a/lib/mv_web/components/layouts/root.html.heex +++ b/lib/mv_web/components/layouts/root.html.heex @@ -1,5 +1,5 @@ - + {Application.get_env(:live_debugger, :live_debugger_tags)} @@ -9,11 +9,29 @@ <.live_title default="Mv" suffix=" ยท Phoenix Framework"> {assigns[:page_title]} - - + - + {@inner_content} diff --git a/lib/mv_web/endpoint.ex b/lib/mv_web/endpoint.ex index 090e54c..97dcae4 100644 --- a/lib/mv_web/endpoint.ex +++ b/lib/mv_web/endpoint.ex @@ -17,12 +17,13 @@ defmodule MvWeb.Endpoint do # Serve at "/" the static files from "priv/static" directory. # - # You should set gzip to true if you are running phx.digest - # when deploying your static files in production. + # When code reloading is disabled (e.g., in production), + # the `gzip` option is enabled to serve compressed + # static files generated by running `phx.digest`. plug Plug.Static, at: "/", from: :mv, - gzip: false, + gzip: not code_reloading?, only: MvWeb.static_paths() if Code.ensure_loaded?(Tidewave) do diff --git a/mix.exs b/mix.exs index 2284006..6fe5a67 100644 --- a/mix.exs +++ b/mix.exs @@ -5,12 +5,13 @@ defmodule Mv.MixProject do [ app: :mv, version: "0.1.0", - elixir: "~> 1.14", + elixir: "~> 1.15", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, consolidate_protocols: Mix.env() != :dev, aliases: aliases(), - deps: deps() + deps: deps(), + listeners: [Phoenix.CodeReloader] ] end @@ -44,26 +45,26 @@ defmodule Mv.MixProject do {:ash_authentication, "~> 4.9"}, {:ash_authentication_phoenix, "~> 2.10"}, {:igniter, "~> 0.6", only: [:dev, :test]}, - {:phoenix, "~> 1.7.20"}, + {:phoenix, "~> 1.8.0-rc.3", override: true}, {:phoenix_ecto, "~> 4.5"}, {:ecto_sql, "~> 3.10"}, {:postgrex, ">= 0.0.0"}, {:phoenix_html, "~> 4.1"}, {:phoenix_live_reload, "~> 1.2", only: :dev}, - {:phoenix_live_view, "~> 1.0.0"}, + {:phoenix_live_view, "~> 1.0.9"}, {:floki, ">= 0.30.0", only: :test}, {:phoenix_live_dashboard, "~> 0.8.3"}, - {:esbuild, "~> 0.10", runtime: Mix.env() == :dev}, - {:tailwind, "~> 0.2", runtime: Mix.env() == :dev}, + {:esbuild, "~> 0.9", runtime: Mix.env() == :dev}, + {:tailwind, "~> 0.3", runtime: Mix.env() == :dev}, {:heroicons, github: "tailwindlabs/heroicons", - tag: "v2.2.0", + tag: "v2.1.1", sparse: "optimized", app: false, compile: false, depth: 1}, - {:swoosh, "~> 1.5"}, - {:finch, "~> 0.20"}, + {:swoosh, "~> 1.16"}, + {:req, "~> 0.5"}, {:telemetry_metrics, "~> 1.0"}, {:telemetry_poller, "~> 1.0"}, {:gettext, "~> 0.26"}, diff --git a/mix.lock b/mix.lock index 6aaec65..fafe9fd 100644 --- a/mix.lock +++ b/mix.lock @@ -30,7 +30,7 @@ "floki": {:hex, :floki, "0.38.0", "62b642386fa3f2f90713f6e231da0fa3256e41ef1089f83b6ceac7a3fd3abf33", [:mix], [], "hexpm", "a5943ee91e93fb2d635b612caf5508e36d37548e84928463ef9dd986f0d1abd9"}, "gettext": {:hex, :gettext, "0.26.2", "5978aa7b21fada6deabf1f6341ddba50bc69c999e812211903b169799208f2a8", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "aa978504bcf76511efdc22d580ba08e2279caab1066b76bb9aa81c4a1e0a32a5"}, "glob_ex": {:hex, :glob_ex, "0.1.11", "cb50d3f1ef53f6ca04d6252c7fde09fd7a1cf63387714fe96f340a1349e62c93", [:mix], [], "hexpm", "342729363056e3145e61766b416769984c329e4378f1d558b63e341020525de4"}, - "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "0435d4ca364a608cc75e2f8683d374e55abbae26", [tag: "v2.2.0", sparse: "optimized", depth: 1]}, + "heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "88ab3a0d790e6a47404cba02800a6b25d2afae50", [tag: "v2.1.1", sparse: "optimized", depth: 1]}, "hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"}, "igniter": {:hex, :igniter, "0.6.19", "d87703b36890bc4278341d966a7ed8e10604a18610a4331ac10c75d1af48fff4", [:mix], [{:glob_ex, "~> 0.1.7", [hex: :glob_ex, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:owl, "~> 0.11", [hex: :owl, repo: "hexpm", optional: false]}, {:phx_new, "~> 1.7", [hex: :phx_new, repo: "hexpm", optional: true]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:rewrite, ">= 1.1.1 and < 2.0.0-0", [hex: :rewrite, repo: "hexpm", optional: false]}, {:sourceror, "~> 1.4", [hex: :sourceror, repo: "hexpm", optional: false]}, {:spitfire, ">= 0.1.3 and < 1.0.0-0", [hex: :spitfire, repo: "hexpm", optional: false]}], "hexpm", "c2070b3fdbd238fc0a0bfbc1f125b5c0f79a1fe2f5b3c7b43cd33de696783663"}, "inflex": {:hex, :inflex, "2.1.0", "a365cf0821a9dacb65067abd95008ca1b0bb7dcdd85ae59965deef2aa062924c", [:mix], [], "hexpm", "14c17d05db4ee9b6d319b0bff1bdf22aa389a25398d1952c7a0b5f3d93162dd8"}, @@ -47,7 +47,7 @@ "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "owl": {:hex, :owl, "0.12.2", "65906b525e5c3ef51bab6cba7687152be017aebe1da077bb719a5ee9f7e60762", [:mix], [{:ucwidth, "~> 0.2", [hex: :ucwidth, repo: "hexpm", optional: true]}], "hexpm", "6398efa9e1fea70a04d24231e10dcd66c1ac1aa2da418d20ef5357ec61de2880"}, - "phoenix": {:hex, :phoenix, "1.7.21", "14ca4f1071a5f65121217d6b57ac5712d1857e40a0833aff7a691b7870fc9a3b", [: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.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "336dce4f86cba56fed312a7d280bf2282c720abb6074bdb1b61ec8095bdd0bc9"}, + "phoenix": {:hex, :phoenix, "1.8.0-rc.3", "6ae19e57b9c109556f1b8abdb992d96d443b0ae28e03b604f3dc6c75d9f7d35f", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {: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.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "419422afc33e965c0dbf181cbedc77b4cfd024dac0db7d9d2287656043d48e24"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.6.5", "c4ef322acd15a574a8b1a08eff0ee0a85e73096b53ce1403b6563709f15e1cea", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "26ec3208eef407f31b748cadd044045c6fd485fbff168e35963d2f9dfff28d4b"}, "phoenix_html": {:hex, :phoenix_html, "4.2.1", "35279e2a39140068fc03f8874408d58eef734e488fc142153f055c5454fd1c08", [:mix], [], "hexpm", "cff108100ae2715dd959ae8f2a8cef8e20b593f8dfd031c9cba92702cf23e053"}, "phoenix_html_helpers": {:hex, :phoenix_html_helpers, "1.0.1", "7eed85c52eff80a179391036931791ee5d2f713d76a81d0d2c6ebafe1e11e5ec", [:mix], [{:phoenix_html, "~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "cffd2385d1fa4f78b04432df69ab8da63dc5cf63e07b713a4dcf36a3740e3090"},