From 15cd3f41459bd1528986cc6d8a25695875d5f0ce Mon Sep 17 00:00:00 2001 From: APB9785 <74077809+APB9785@users.noreply.github.com> Date: Wed, 23 Aug 2023 11:32:51 -0500 Subject: [PATCH 1/8] Getting started --- lib/beacon/live_admin/content.ex | 4 ++++ .../live/error_page_editor_live/index.ex | 22 +++++++++++++++++++ lib/beacon/live_admin/live/home_live.ex | 7 ++++++ lib/beacon/live_admin/router.ex | 1 + 4 files changed, 34 insertions(+) create mode 100644 lib/beacon/live_admin/live/error_page_editor_live/index.ex diff --git a/lib/beacon/live_admin/content.ex b/lib/beacon/live_admin/content.ex index b749470d..22dd7e33 100644 --- a/lib/beacon/live_admin/content.ex +++ b/lib/beacon/live_admin/content.ex @@ -162,4 +162,8 @@ defmodule Beacon.LiveAdmin.Content do def update_component(site, component, attrs) do call(site, Beacon.Content, :update_component, [component, attrs]) end + + def list_error_pages(site) do + call(site, Beacon.Content, :list_error_pages, [site]) + end end diff --git a/lib/beacon/live_admin/live/error_page_editor_live/index.ex b/lib/beacon/live_admin/live/error_page_editor_live/index.ex new file mode 100644 index 00000000..b16b80be --- /dev/null +++ b/lib/beacon/live_admin/live/error_page_editor_live/index.ex @@ -0,0 +1,22 @@ +defmodule Beacon.LiveAdmin.ErrorPageEditorLive.Index do + @moduledoc false + use Beacon.LiveAdmin.PageBuilder + + alias Beacon.LiveAdmin.Content + + on_mount {Beacon.LiveAdmin.Hooks.Authorized, {:error_pages, :index}} + + def menu_link(_, :index), do: {:root, "Error Pages"} + + def handle_params(_params, _uri, socket) do + error_pages = Content.list_error_pages(socket.assigns.beacon_page.site) + + {:noreply, assign(socket, error_pages: error_pages)} + end + + def render(assigns) do + ~H""" +
Test
+ """ + end +end diff --git a/lib/beacon/live_admin/live/home_live.ex b/lib/beacon/live_admin/live/home_live.ex index d1502016..89c0b0e4 100644 --- a/lib/beacon/live_admin/live/home_live.ex +++ b/lib/beacon/live_admin/live/home_live.ex @@ -49,6 +49,13 @@ defmodule Beacon.LiveAdmin.HomeLive do Components + <.link + href={Beacon.LiveAdmin.Router.beacon_live_admin_path(@socket, site, "/error_pages")} + class="whitespace-nowrap text-sm leading-5 py-3.5 font-bold tracking-widest text-center uppercase bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-blue-200 active:bg-blue-800 px-6 text-gray-50" + > + Error Pages + + <.link href={Beacon.LiveAdmin.Router.beacon_live_admin_path(@socket, site, "/media_library")} class="whitespace-nowrap text-sm leading-5 py-3.5 font-bold tracking-widest text-center uppercase bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-blue-200 active:bg-blue-800 px-6 text-gray-50" diff --git a/lib/beacon/live_admin/router.ex b/lib/beacon/live_admin/router.ex index b01fb021..a492846a 100644 --- a/lib/beacon/live_admin/router.ex +++ b/lib/beacon/live_admin/router.ex @@ -144,6 +144,7 @@ defmodule Beacon.LiveAdmin.Router do {"/components", Beacon.LiveAdmin.ComponentEditorLive.Index, :index, %{}}, {"/components/new", Beacon.LiveAdmin.ComponentEditorLive.New, :new, %{}}, {"/components/:id", Beacon.LiveAdmin.ComponentEditorLive.Edit, :edit, %{}}, + {"/error_pages", Beacon.LiveAdmin.ErrorPageEditorLive.Index, :index, %{}}, {"/media_library", Beacon.LiveAdmin.MediaLibraryLive.Index, :index, %{}}, {"/media_library/upload", Beacon.LiveAdmin.MediaLibraryLive.Index, :upload, %{}}, {"/media_library/:id", Beacon.LiveAdmin.MediaLibraryLive.Index, :show, %{}} From b3e0eff1e734e42f9042d92666f8d25bc8d00dac Mon Sep 17 00:00:00 2001 From: APB9785 <74077809+APB9785@users.noreply.github.com> Date: Wed, 23 Aug 2023 16:46:45 -0500 Subject: [PATCH 2/8] Liveview + tests --- lib/beacon/live_admin/content.ex | 16 ++ .../live/error_page_editor_live/index.ex | 254 +++++++++++++++++- lib/beacon/live_admin/page_live.ex | 2 + lib/beacon/live_admin/router.ex | 1 + .../error_page_editor_live/index_test.exs | 58 ++++ test/support/fixtures.ex | 14 + 6 files changed, 340 insertions(+), 5 deletions(-) create mode 100644 test/beacon/live_admin/live/error_page_editor_live/index_test.exs diff --git a/lib/beacon/live_admin/content.ex b/lib/beacon/live_admin/content.ex index 22dd7e33..f643c2a0 100644 --- a/lib/beacon/live_admin/content.ex +++ b/lib/beacon/live_admin/content.ex @@ -163,7 +163,23 @@ defmodule Beacon.LiveAdmin.Content do call(site, Beacon.Content, :update_component, [component, attrs]) end + def change_error_page(site, error_page, attrs \\ %{}) do + call(site, Beacon.Content, :change_error_page, [error_page, attrs]) + end + + def create_error_page(site, attrs) do + call(site, Beacon.Content, :create_error_page, [attrs]) + end + def list_error_pages(site) do call(site, Beacon.Content, :list_error_pages, [site]) end + + def update_error_page(site, error_page, attrs) do + call(site, Beacon.Content, :update_error_page, [error_page, attrs]) + end + + def delete_error_page(site, error_page) do + call(site, Beacon.Content, :delete_error_page, [error_page]) + end end diff --git a/lib/beacon/live_admin/live/error_page_editor_live/index.ex b/lib/beacon/live_admin/live/error_page_editor_live/index.ex index b16b80be..aa10b9be 100644 --- a/lib/beacon/live_admin/live/error_page_editor_live/index.ex +++ b/lib/beacon/live_admin/live/error_page_editor_live/index.ex @@ -4,19 +4,263 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.Index do alias Beacon.LiveAdmin.Content - on_mount {Beacon.LiveAdmin.Hooks.Authorized, {:error_pages, :index}} + on_mount({Beacon.LiveAdmin.Hooks.Authorized, {:error_pages, :index}}) def menu_link(_, :index), do: {:root, "Error Pages"} - def handle_params(_params, _uri, socket) do - error_pages = Content.list_error_pages(socket.assigns.beacon_page.site) + def handle_params(params, _uri, socket) do + %{beacon_page: %{site: site}} = socket.assigns - {:noreply, assign(socket, error_pages: error_pages)} + socket = + socket + |> assign(page_title: "Error Pages") + |> assign(unsaved_changes: false) + |> assign(show_create_modal: false) + |> assign(show_nav_modal: false) + |> assign(show_delete_modal: false) + |> assign(show_status_change_field: false) + |> assign(create_form: to_form(%{}, as: :error_page)) + |> assign_new(:error_pages, fn -> Content.list_error_pages(site) end) + |> assign_new(:layouts, fn -> Content.list_layouts(site) end) + |> assign_selected(params["status"]) + |> assign_form() + + {:noreply, socket} + end + + def handle_event("select-" <> status, _, socket) do + %{beacon_page: %{site: site}} = socket.assigns + + path = beacon_live_admin_path(socket, site, "/error_pages/#{status}") + + if socket.assigns.unsaved_changes do + {:noreply, assign(socket, show_nav_modal: true, confirm_nav_path: path)} + else + {:noreply, push_redirect(socket, to: path)} + end + end + + def handle_event("error_page_template_editor_lost_focus", %{"value" => template}, socket) do + %{selected: selected, beacon_page: %{site: site}, form: form} = socket.assigns + + changeset = + site + |> Content.change_error_page(selected, %{ + "site" => site, + "template" => template, + "status" => form.params["status"] || Map.fetch!(form.data, :status), + "layout_id" => form.params["layout_id"] || Map.fetch!(form.data, :layout_id) + }) + |> Map.put(:action, :validate) + + socket = + socket + |> assign(form: to_form(changeset)) + |> assign(changed_template: template) + |> assign(unsaved_changes: !(changeset.changes == %{})) + + {:noreply, socket} + end + + def handle_event("create_new", _, socket) do + {:noreply, assign(socket, show_create_modal: true)} + end + + def handle_event("change_status", _, socket) do + {:noreply, assign(socket, show_status_change_field: true)} + end + + def handle_event("save_new", %{"status" => status}, socket) do + %{beacon_page: %{site: site}, layouts: layouts} = socket.assigns + + attrs = %{ + "status" => status, + "site" => site, + "template" => "Something went wrong", + "layout_id" => Enum.find(layouts, &(&1.title == "Default")).id + } + + socket = + case Content.create_error_page(site, attrs) do + {:ok, _} -> + socket + |> assign(error_pages: Content.list_error_pages(site)) + |> assign_selected(status) + |> assign(show_create_modal: false) + |> push_patch(to: beacon_live_admin_path(socket, site, "/error_pages/#{status}")) + + {:error, changeset} -> + assign(socket, create_form: to_form(changeset)) + end + + {:noreply, socket} + end + + def handle_event("save_changes", params, socket) do + %{selected: selected, beacon_page: %{site: site}} = socket.assigns + + attrs = %{layout_id: params["layout_id"], template: params["template"]} + + socket = + case Content.update_error_page(site, selected, attrs) do + {:ok, _} -> + socket + |> assign_selected(selected.status) + |> assign_form() + |> assign(unsaved_changes: false) + + {:error, changeset} -> + changeset = Map.put(changeset, :action, :update) + assign(socket, form: to_form(changeset)) + end + + {:noreply, socket} + end + + def handle_event("delete", _, socket) do + {:noreply, assign(socket, show_delete_modal: true)} + end + + def handle_event("delete_confirm", _, socket) do + %{selected: error_page, beacon_page: %{site: site}} = socket.assigns + + {:ok, _} = Content.delete_error_page(site, error_page) + + socket = + socket + |> assign(error_pages: Content.list_error_pages(site)) + |> push_patch(to: beacon_live_admin_path(socket, site, "/error_pages")) + + {:noreply, socket} + end + + def handle_event("delete_cancel", _, socket) do + {:noreply, assign(socket, show_delete_modal: false)} + end + + def handle_event("stay_here", _params, socket) do + {:noreply, assign(socket, show_nav_modal: false, confirm_nav_path: nil)} + end + + def handle_event("discard_changes", _params, socket) do + {:noreply, push_redirect(socket, to: socket.assigns.confirm_nav_path)} + end + + def handle_event("cancel_create", _params, socket) do + {:noreply, assign(socket, show_create_modal: false)} + end + + defp assign_selected(socket, nil) do + case socket.assigns.error_pages do + [] -> assign(socket, selected: nil, changed_template: "") + [hd | _] -> assign(socket, selected: hd, changed_template: hd.template) + end + end + + defp assign_selected(socket, status_str) do + selected = Enum.find(socket.assigns.error_pages, &("#{&1.status}" == status_str)) + assign(socket, selected: selected, changed_template: selected.template) + end + + defp assign_form(socket) do + form = + case socket.assigns do + %{selected: nil} -> + nil + + %{selected: selected, beacon_page: %{site: site}} -> + site + |> Content.change_error_page(selected) + |> to_form() + end + + assign(socket, form: form) end def render(assigns) do ~H""" -
Test
+
+ <.header> + <%= @page_title %> + <:actions> + <.button phx-disable-with="Saving..." form="error-page-form" class="uppercase">Save Changes + + <:actions> + <.button type="button" id="delete-error-page-button" phx-click="delete" phx-disable-with="Deleting..." class="uppercase">Delete + + + + <.modal :if={@show_nav_modal} id="confirm-nav" on_cancel={JS.push("stay_here")} show> +

You've made unsaved changes to this error page!

+

Navigating to another error page without saving will cause these changes to be lost.

+ <.button type="button" phx-click="stay_here"> + Stay here + + <.button type="button" phx-click="discard_changes"> + Discard changes + + + + <.modal :if={@show_create_modal} id="create-modal" on_cancel={JS.push("cancel_create")} show> + <.simple_form :let={f} for={@create_form} id="create-form" phx-submit="save_new"> + <.input field={f[:status]} type="number" label="Status code for new error page:" /> + <:actions> + <.button>Save + + + + + <.modal :if={@show_delete_modal} id="delete-modal" on_cancel={JS.push("delete_cancel")} show> +

Are you sure you want to delete this error page?

+ <.button type="button" id="confirm-delete-button" phx-click="delete_confirm"> + Delete + + <.button type="button" phx-click="delete_cancel"> + Cancel + + + +
+
+ <.button type="button" id="new-error-page-button" phx-click="create_new"> + New Error Page + + <.table id="error-pages" rows={@error_pages} row_click={fn row -> "select-#{row.status}" end}> + <:col :let={error_page} label="status"> + <%= Map.fetch!(error_page, :status) %> + + +
+ +
+ <.form :let={f} for={@form} id="error-page-form" class="items-center" phx-submit="save_changes"> +
+
+ Status: <%= @selected.status %> +
+
+
+
+ Layout: +
+ <.input type="select" field={f[:layout_id]} name="error_page[layout_id]" options={Enum.map(@layouts, &{&1.title, &1.id})} value={@selected.layout_id} /> +
+ <.input type="hidden" field={f[:template]} name="error_page[template]" id="error_page-form_template" value={@changed_template} /> + + +
+
+ "html"})} + /> +
+
+
+
+
""" end end diff --git a/lib/beacon/live_admin/page_live.ex b/lib/beacon/live_admin/page_live.ex index c4fc24e5..aed5465a 100644 --- a/lib/beacon/live_admin/page_live.ex +++ b/lib/beacon/live_admin/page_live.ex @@ -137,6 +137,8 @@ defmodule Beacon.LiveAdmin.PageLive do {_, "/pages"} -> false {"/components", _} -> true {_, "/components"} -> false + {"/error_pages", _} -> true + {_, "/error_pages"} -> false {"/media_library", _} -> true {_, "/media_library"} -> false {a, b} -> a <= b diff --git a/lib/beacon/live_admin/router.ex b/lib/beacon/live_admin/router.ex index a492846a..eef9e974 100644 --- a/lib/beacon/live_admin/router.ex +++ b/lib/beacon/live_admin/router.ex @@ -145,6 +145,7 @@ defmodule Beacon.LiveAdmin.Router do {"/components/new", Beacon.LiveAdmin.ComponentEditorLive.New, :new, %{}}, {"/components/:id", Beacon.LiveAdmin.ComponentEditorLive.Edit, :edit, %{}}, {"/error_pages", Beacon.LiveAdmin.ErrorPageEditorLive.Index, :index, %{}}, + {"/error_pages/:status", Beacon.LiveAdmin.ErrorPageEditorLive.Index, :index, %{}}, {"/media_library", Beacon.LiveAdmin.MediaLibraryLive.Index, :index, %{}}, {"/media_library/upload", Beacon.LiveAdmin.MediaLibraryLive.Index, :upload, %{}}, {"/media_library/:id", Beacon.LiveAdmin.MediaLibraryLive.Index, :show, %{}} diff --git a/test/beacon/live_admin/live/error_page_editor_live/index_test.exs b/test/beacon/live_admin/live/error_page_editor_live/index_test.exs new file mode 100644 index 00000000..cabc90bd --- /dev/null +++ b/test/beacon/live_admin/live/error_page_editor_live/index_test.exs @@ -0,0 +1,58 @@ +defmodule Beacon.LiveAdmin.ErrorPageEditorLive.IndexTest do + use Beacon.LiveAdmin.ConnCase, async: false + + import Beacon.LiveAdminTest.Cluster, only: [rpc: 4] + + setup do + default_layout = layout_fixture(node1(), %{title: "Default"}) + _another_layout = layout_fixture(node1(), %{title: "Another"}) + attrs = %{status: 404, layout_id: default_layout.id, template: "Not Found"} + error_page_fixture(node1(), attrs) + attrs = %{status: 500, layout_id: default_layout.id, template: "Internal Server Error"} + error_page_fixture(node1(), attrs) + + on_exit(fn -> + rpc(node1(), Beacon.Repo, :delete_all, [Beacon.Content.ErrorPage, [log: false]]) + rpc(node1(), Beacon.Repo, :delete_all, [Beacon.Content.Layout, [log: false]]) + end) + end + + test "select error page via path", %{conn: conn} do + {:ok, view, _html} = live(conn, "/admin/site_a/error_pages") + assert has_element?(view, "#status-display", "Status: 404") + + {:ok, view, _html} = live(conn, "/admin/site_a/error_pages/404") + assert has_element?(view, "#status-display", "Status: 404") + + {:ok, view, _html} = live(conn, "/admin/site_a/error_pages/500") + assert has_element?(view, "#status-display", "Status: 500") + end + + test "create a new error page", %{conn: conn} do + {:ok, view, _html} = live(conn, "/admin/site_a/error_pages") + + view |> element("#new-error-page-button") |> render_click() + + assert has_element?(view, "#create-modal") + + view |> form("#create-form", %{status: 400}) |> render_submit() + + refute has_element?(view, "#create-modal") + assert has_element?(view, "#status-display", "Status: 400") + end + + test "delete error page", %{conn: conn} do + {:ok, view, _html} = live(conn, "/admin/site_a/error_pages/500") + + assert has_element?(view, "span", "500") + + view |> element("#delete-error-page-button") |> render_click() + + assert has_element?(view, "#delete-modal") + + view |> element("#confirm-delete-button") |> render_click() + + refute has_element?(view, "#delete-modal") + refute has_element?(view, "span", "500") + end +end diff --git a/test/support/fixtures.ex b/test/support/fixtures.ex index 4e62708e..2acec53d 100644 --- a/test/support/fixtures.ex +++ b/test/support/fixtures.ex @@ -42,6 +42,20 @@ defmodule Beacon.LiveAdmin.Fixtures do rpc(node, Beacon.Content, :create_page!, [attrs]) end + def error_page_fixture(node \\ node1(), attrs \\ %{}) do + layout_id = get_lazy(attrs, :layout_id, fn -> layout_fixture().id end) + + attrs = + Enum.into(attrs, %{ + site: "site_a", + status: Enum.random(111..999), + layout_id: layout_id, + template: "Oops" + }) + + rpc(node, Beacon.Content, :create_error_page!, [attrs]) + end + def media_library_asset_fixture(node \\ node1(), attrs \\ %{}) do file_metadata = file_metadata_fixture(node, attrs) rpc(node, Beacon.MediaLibrary, :upload, [file_metadata]) From 6394ce75c7e50c5cfa20676102a57e4f5abdcfc9 Mon Sep 17 00:00:00 2001 From: APB9785 <74077809+APB9785@users.noreply.github.com> Date: Thu, 24 Aug 2023 13:59:37 -0500 Subject: [PATCH 3/8] Success message --- .../live/error_page_editor_live/index.ex | 28 +++++++++++++++---- .../error_page_editor_live/index_test.exs | 19 ++++++++++++- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/lib/beacon/live_admin/live/error_page_editor_live/index.ex b/lib/beacon/live_admin/live/error_page_editor_live/index.ex index aa10b9be..9e9e7ce7 100644 --- a/lib/beacon/live_admin/live/error_page_editor_live/index.ex +++ b/lib/beacon/live_admin/live/error_page_editor_live/index.ex @@ -87,7 +87,7 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.Index do |> assign(error_pages: Content.list_error_pages(site)) |> assign_selected(status) |> assign(show_create_modal: false) - |> push_patch(to: beacon_live_admin_path(socket, site, "/error_pages/#{status}")) + |> push_redirect(to: beacon_live_admin_path(socket, site, "/error_pages/#{status}")) {:error, changeset} -> assign(socket, create_form: to_form(changeset)) @@ -96,18 +96,20 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.Index do {:noreply, socket} end - def handle_event("save_changes", params, socket) do + def handle_event("save_changes", %{"error_page" => params}, socket) do %{selected: selected, beacon_page: %{site: site}} = socket.assigns attrs = %{layout_id: params["layout_id"], template: params["template"]} socket = case Content.update_error_page(site, selected, attrs) do - {:ok, _} -> + {:ok, updated_error_page} -> socket + |> assign_error_page_update(updated_error_page) |> assign_selected(selected.status) |> assign_form() |> assign(unsaved_changes: false) + |> put_flash(:info, "Error page updated successfully") {:error, changeset} -> changeset = Map.put(changeset, :action, :update) @@ -157,8 +159,12 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.Index do end end - defp assign_selected(socket, status_str) do - selected = Enum.find(socket.assigns.error_pages, &("#{&1.status}" == status_str)) + defp assign_selected(socket, status) when is_binary(status) do + assign_selected(socket, String.to_integer(status)) + end + + defp assign_selected(socket, status) when is_integer(status) do + selected = Enum.find(socket.assigns.error_pages, &(&1.status == status)) assign(socket, selected: selected, changed_template: selected.template) end @@ -177,6 +183,18 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.Index do assign(socket, form: form) end + defp assign_error_page_update(socket, updated_error_page) do + %{id: error_page_id} = updated_error_page + + error_pages = + Enum.map(socket.assigns.error_pages, fn + %{id: ^error_page_id} -> updated_error_page + other -> other + end) + + assign(socket, error_pages: error_pages) + end + def render(assigns) do ~H"""
diff --git a/test/beacon/live_admin/live/error_page_editor_live/index_test.exs b/test/beacon/live_admin/live/error_page_editor_live/index_test.exs index cabc90bd..bfa837d2 100644 --- a/test/beacon/live_admin/live/error_page_editor_live/index_test.exs +++ b/test/beacon/live_admin/live/error_page_editor_live/index_test.exs @@ -5,7 +5,7 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.IndexTest do setup do default_layout = layout_fixture(node1(), %{title: "Default"}) - _another_layout = layout_fixture(node1(), %{title: "Another"}) + another_layout = layout_fixture(node1(), %{title: "Another"}) attrs = %{status: 404, layout_id: default_layout.id, template: "Not Found"} error_page_fixture(node1(), attrs) attrs = %{status: 500, layout_id: default_layout.id, template: "Internal Server Error"} @@ -15,6 +15,8 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.IndexTest do rpc(node1(), Beacon.Repo, :delete_all, [Beacon.Content.ErrorPage, [log: false]]) rpc(node1(), Beacon.Repo, :delete_all, [Beacon.Content.Layout, [log: false]]) end) + + [another_layout: another_layout] end test "select error page via path", %{conn: conn} do @@ -41,6 +43,21 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.IndexTest do assert has_element?(view, "#status-display", "Status: 400") end + test "update an error page", %{conn: conn, another_layout: layout} do + {:ok, view, html} = live(conn, "/admin/site_a/error_pages/404") + + assert has_element?(view, "[selected=\"selected\"]", "Default") + + view + |> form("#error-page-form", error_page: %{layout_id: layout.id}) + |> render_submit() + + assert has_element?(view, "p", "Error page updated successfully") + + refute has_element?(view, "[selected=\"selected\"]", "Default") + assert has_element?(view, "[selected=\"selected\"]", "Another") + end + test "delete error page", %{conn: conn} do {:ok, view, _html} = live(conn, "/admin/site_a/error_pages/500") From e20444a36f8fd9b8ecf0483fcc1296401297cc87 Mon Sep 17 00:00:00 2001 From: APB9785 <74077809+APB9785@users.noreply.github.com> Date: Tue, 29 Aug 2023 11:47:27 -0500 Subject: [PATCH 4/8] Fix test --- .../live_admin/live/error_page_editor_live/index_test.exs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/beacon/live_admin/live/error_page_editor_live/index_test.exs b/test/beacon/live_admin/live/error_page_editor_live/index_test.exs index bfa837d2..602bf082 100644 --- a/test/beacon/live_admin/live/error_page_editor_live/index_test.exs +++ b/test/beacon/live_admin/live/error_page_editor_live/index_test.exs @@ -37,7 +37,11 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.IndexTest do assert has_element?(view, "#create-modal") - view |> form("#create-form", %{status: 400}) |> render_submit() + {:ok, view, _html} = + view + |> form("#create-form", %{status: 400}) + |> render_submit() + |> follow_redirect(conn, "/admin/site_a/error_pages/400") refute has_element?(view, "#create-modal") assert has_element?(view, "#status-display", "Status: 400") From 671d4477395ea2a9ac9fedb6b833ba6295d1d8a6 Mon Sep 17 00:00:00 2001 From: APB9785 <74077809+APB9785@users.noreply.github.com> Date: Tue, 29 Aug 2023 11:47:43 -0500 Subject: [PATCH 5/8] Select from valid error statuses --- lib/beacon/live_admin/content.ex | 4 ++++ lib/beacon/live_admin/live/error_page_editor_live/index.ex | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/beacon/live_admin/content.ex b/lib/beacon/live_admin/content.ex index f643c2a0..e688448a 100644 --- a/lib/beacon/live_admin/content.ex +++ b/lib/beacon/live_admin/content.ex @@ -182,4 +182,8 @@ defmodule Beacon.LiveAdmin.Content do def delete_error_page(site, error_page) do call(site, Beacon.Content, :delete_error_page, [error_page]) end + + def valid_error_statuses(site) do + call(site, Beacon.Content.ErrorPage, :valid_statuses, []) + end end diff --git a/lib/beacon/live_admin/live/error_page_editor_live/index.ex b/lib/beacon/live_admin/live/error_page_editor_live/index.ex index 9e9e7ce7..4c611f93 100644 --- a/lib/beacon/live_admin/live/error_page_editor_live/index.ex +++ b/lib/beacon/live_admin/live/error_page_editor_live/index.ex @@ -221,7 +221,7 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.Index do <.modal :if={@show_create_modal} id="create-modal" on_cancel={JS.push("cancel_create")} show> <.simple_form :let={f} for={@create_form} id="create-form" phx-submit="save_new"> - <.input field={f[:status]} type="number" label="Status code for new error page:" /> + <.input field={f[:status]} type="select" label="Status code for new error page:" options={Content.valid_error_statuses(@beacon_page.site)} /> <:actions> <.button>Save From 214b7d7773050e6c86863da608f0f5b54ee19c02 Mon Sep 17 00:00:00 2001 From: Leandro Pereira Date: Tue, 17 Oct 2023 16:55:39 -0400 Subject: [PATCH 6/8] update layout --- .../live/error_page_editor_live/index.ex | 128 ++++++++---------- lib/beacon/live_admin/live/home_live.ex | 9 +- lib/beacon/live_admin/page_live.ex | 4 +- lib/beacon/live_admin/router.ex | 11 +- mix.lock | 1 + .../error_page_editor_live/index_test.exs | 8 +- 6 files changed, 80 insertions(+), 81 deletions(-) diff --git a/lib/beacon/live_admin/live/error_page_editor_live/index.ex b/lib/beacon/live_admin/live/error_page_editor_live/index.ex index 4c611f93..6afeb76a 100644 --- a/lib/beacon/live_admin/live/error_page_editor_live/index.ex +++ b/lib/beacon/live_admin/live/error_page_editor_live/index.ex @@ -201,83 +201,75 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.Index do <.header> <%= @page_title %> <:actions> - <.button phx-disable-with="Saving..." form="error-page-form" class="uppercase">Save Changes - - <:actions> - <.button type="button" id="delete-error-page-button" phx-click="delete" phx-disable-with="Deleting..." class="uppercase">Delete + <.button type="button" id="new-error-page-button" phx-click="create_new" class="uppercase"> + New Error Page + - <.modal :if={@show_nav_modal} id="confirm-nav" on_cancel={JS.push("stay_here")} show> -

You've made unsaved changes to this error page!

-

Navigating to another error page without saving will cause these changes to be lost.

- <.button type="button" phx-click="stay_here"> - Stay here - - <.button type="button" phx-click="discard_changes"> - Discard changes - - - - <.modal :if={@show_create_modal} id="create-modal" on_cancel={JS.push("cancel_create")} show> - <.simple_form :let={f} for={@create_form} id="create-form" phx-submit="save_new"> - <.input field={f[:status]} type="select" label="Status code for new error page:" options={Content.valid_error_statuses(@beacon_page.site)} /> - <:actions> - <.button>Save - - - - - <.modal :if={@show_delete_modal} id="delete-modal" on_cancel={JS.push("delete_cancel")} show> -

Are you sure you want to delete this error page?

- <.button type="button" id="confirm-delete-button" phx-click="delete_confirm"> - Delete - - <.button type="button" phx-click="delete_cancel"> - Cancel - - - -
-
- <.button type="button" id="new-error-page-button" phx-click="create_new"> - New Error Page + <.main_content class="h-[calc(100vh_-_223px)]"> + <.modal :if={@show_nav_modal} id="confirm-nav" on_cancel={JS.push("stay_here")} show> +

You've made unsaved changes to this error page!

+

Navigating to another error page without saving will cause these changes to be lost.

+ <.button type="button" phx-click="stay_here"> + Stay here - <.table id="error-pages" rows={@error_pages} row_click={fn row -> "select-#{row.status}" end}> - <:col :let={error_page} label="status"> - <%= Map.fetch!(error_page, :status) %> - - -
+ <.button type="button" phx-click="discard_changes"> + Discard changes + + + + <.modal :if={@show_create_modal} id="create-modal" on_cancel={JS.push("cancel_create")} show> + <.simple_form :let={f} for={@create_form} id="create-form" phx-submit="save_new"> + <.input field={f[:status]} type="select" label="Status code for new error page:" options={Content.valid_error_statuses(@beacon_page.site)} /> + <:actions> + <.button>Save + + + + + <.modal :if={@show_delete_modal} id="delete-modal" on_cancel={JS.push("delete_cancel")} show> +

Are you sure you want to delete this error page?

+ <.button type="button" id="confirm-delete-button" phx-click="delete_confirm"> + Delete + + <.button type="button" phx-click="delete_cancel"> + Cancel + + + +
+
+ <.table id="error-pages" rows={@error_pages} row_click={fn row -> "select-#{row.status}" end}> + <:col :let={error_page} label="status"> + <%= Map.fetch!(error_page, :status) %> + + +
-
- <.form :let={f} for={@form} id="error-page-form" class="items-center" phx-submit="save_changes"> -
-
- Status: <%= @selected.status %> +
+ <.form :let={f} for={@form} id="error-page-form" class="flex items-end gap-4" phx-submit="save_changes"> + <.input label="Status" field={f[:status]} type="text" disabled readonly /> + <.input label="Layout" field={f[:layout_id]} options={Enum.map(@layouts, &{&1.title, &1.id})} value={@selected.layout_id} type="select" /> + <.input type="hidden" field={f[:template]} name="error_page[template]" id="error_page-form_template" value={@changed_template} /> + + <.button phx-disable-with="Saving..." class="ml-auto">Save Changes + <.button id="delete-error-page-button" type="button" phx-click="delete" class="">Delete + + +
+
+ "html"})} + />
-
-
- Layout: -
- <.input type="select" field={f[:layout_id]} name="error_page[layout_id]" options={Enum.map(@layouts, &{&1.title, &1.id})} value={@selected.layout_id} /> -
- <.input type="hidden" field={f[:template]} name="error_page[template]" id="error_page-form_template" value={@changed_template} /> - - -
-
- "html"})} - /> -
-
+
""" end diff --git a/lib/beacon/live_admin/live/home_live.ex b/lib/beacon/live_admin/live/home_live.ex index ab02220c..8aefe83e 100644 --- a/lib/beacon/live_admin/live/home_live.ex +++ b/lib/beacon/live_admin/live/home_live.ex @@ -42,18 +42,19 @@ defmodule Beacon.LiveAdmin.HomeLive do <.link - href={Beacon.LiveAdmin.Router.beacon_live_admin_path(@socket, site, "/pages")} + href={Beacon.LiveAdmin.Router.beacon_live_admin_path(@socket, site, "/components")} class="whitespace-nowrap text-sm leading-5 py-3.5 font-bold tracking-widest text-center uppercase bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-blue-200 active:bg-blue-800 px-6 text-gray-50" > - Pages + Components <.link - href={Beacon.LiveAdmin.Router.beacon_live_admin_path(@socket, site, "/components")} + href={Beacon.LiveAdmin.Router.beacon_live_admin_path(@socket, site, "/pages")} class="whitespace-nowrap text-sm leading-5 py-3.5 font-bold tracking-widest text-center uppercase bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-blue-200 active:bg-blue-800 px-6 text-gray-50" > - Components + Pages + <.link href={Beacon.LiveAdmin.Router.beacon_live_admin_path(@socket, site, "/error_pages")} class="whitespace-nowrap text-sm leading-5 py-3.5 font-bold tracking-widest text-center uppercase bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus-visible:ring-4 focus-visible:ring-blue-200 active:bg-blue-800 px-6 text-gray-50" diff --git a/lib/beacon/live_admin/page_live.ex b/lib/beacon/live_admin/page_live.ex index be3597c2..2e1c0256 100644 --- a/lib/beacon/live_admin/page_live.ex +++ b/lib/beacon/live_admin/page_live.ex @@ -148,10 +148,10 @@ defmodule Beacon.LiveAdmin.PageLive do case {a, b} do {"/layouts", _} -> true {_, "/layouts"} -> false - {"/pages", _} -> true - {_, "/pages"} -> false {"/components", _} -> true {_, "/components"} -> false + {"/pages", _} -> true + {_, "/pages"} -> false {"/error_pages", _} -> true {_, "/error_pages"} -> false {"/media_library", _} -> true diff --git a/lib/beacon/live_admin/router.ex b/lib/beacon/live_admin/router.ex index eef9e974..4c156e45 100644 --- a/lib/beacon/live_admin/router.ex +++ b/lib/beacon/live_admin/router.ex @@ -122,6 +122,7 @@ defmodule Beacon.LiveAdmin.Router do end) [ + # layouts {"/layouts", Beacon.LiveAdmin.LayoutEditorLive.Index, :index, %{}}, {"/layouts/new", Beacon.LiveAdmin.LayoutEditorLive.New, :new, %{}}, {"/layouts/:id", Beacon.LiveAdmin.LayoutEditorLive.Edit, :edit, %{}}, @@ -129,6 +130,11 @@ defmodule Beacon.LiveAdmin.Router do {"/layouts/:id/revisions", Beacon.LiveAdmin.LayoutEditorLive.Revisions, :revisions, %{}}, {"/layouts/:id/resource_links", Beacon.LiveAdmin.LayoutEditorLive.ResourceLinks, :resource_links, %{}}, + # components + {"/components", Beacon.LiveAdmin.ComponentEditorLive.Index, :index, %{}}, + {"/components/new", Beacon.LiveAdmin.ComponentEditorLive.New, :new, %{}}, + {"/components/:id", Beacon.LiveAdmin.ComponentEditorLive.Edit, :edit, %{}}, + # pages {"/pages", Beacon.LiveAdmin.PageEditorLive.Index, :index, %{}}, {"/pages/new", Beacon.LiveAdmin.PageEditorLive.New, :new, %{}}, {"/pages/:id", Beacon.LiveAdmin.PageEditorLive.Edit, :edit, %{}}, @@ -141,11 +147,10 @@ defmodule Beacon.LiveAdmin.Router do {"/pages/:page_id/variants", Beacon.LiveAdmin.PageEditorLive.Variants, :variants, %{}}, {"/pages/:page_id/variants/:variant_id", Beacon.LiveAdmin.PageEditorLive.Variants, :variants, %{}}, - {"/components", Beacon.LiveAdmin.ComponentEditorLive.Index, :index, %{}}, - {"/components/new", Beacon.LiveAdmin.ComponentEditorLive.New, :new, %{}}, - {"/components/:id", Beacon.LiveAdmin.ComponentEditorLive.Edit, :edit, %{}}, + # error pages {"/error_pages", Beacon.LiveAdmin.ErrorPageEditorLive.Index, :index, %{}}, {"/error_pages/:status", Beacon.LiveAdmin.ErrorPageEditorLive.Index, :index, %{}}, + # media library {"/media_library", Beacon.LiveAdmin.MediaLibraryLive.Index, :index, %{}}, {"/media_library/upload", Beacon.LiveAdmin.MediaLibraryLive.Index, :upload, %{}}, {"/media_library/:id", Beacon.LiveAdmin.MediaLibraryLive.Index, :show, %{}} diff --git a/mix.lock b/mix.lock index c0ef99fe..0dd4079d 100644 --- a/mix.lock +++ b/mix.lock @@ -17,6 +17,7 @@ "esbuild": {:hex, :esbuild, "0.7.1", "fa0947e8c3c3c2f86c9bf7e791a0a385007ccd42b86885e8e893bdb6631f5169", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "66661cdf70b1378ee4dc16573fcee67750b59761b2605a0207c267ab9d19f13c"}, "ex_aws": {:hex, :ex_aws, "2.4.3", "6c6d88ba7b9c07e3b0f4b70406d5fccb9f5358f5ef18138f7bd396f7863e8255", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "67f61f8b6aec740150d483a21f551fabce26a481d9917305ed2bb47717007519"}, "ex_aws_s3": {:hex, :ex_aws_s3, "2.4.0", "ce8decb6b523381812798396bc0e3aaa62282e1b40520125d1f4eff4abdff0f4", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "85dda6e27754d94582869d39cba3241d9ea60b6aa4167f9c88e309dc687e56bb"}, + "ex_brotli": {:hex, :ex_brotli, "0.3.0", "69d5f3720df70d5c89d1395d8fbe49ba37466b626834aaf6d77c72e0c93cf975", [:mix], [{:phoenix, ">= 0.0.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:rustler, "~> 0.29", [hex: :rustler, repo: "hexpm", optional: true]}, {:rustler_precompiled, "~> 0.6", [hex: :rustler_precompiled, repo: "hexpm", optional: false]}], "hexpm", "8e46982f7d20069419ca8c8c54f9f3ebd9fa0e1d094c54cbf8ce3d636d84dfa7"}, "expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, "floki": {:hex, :floki, "0.34.3", "5e2dcaec5d7c228ce5b1d3501502e308b2d79eb655e4191751a1fe491c37feac", [:mix], [], "hexpm", "9577440eea5b97924b4bf3c7ea55f7b8b6dce589f9b28b096cc294a8dc342341"}, diff --git a/test/beacon/live_admin/live/error_page_editor_live/index_test.exs b/test/beacon/live_admin/live/error_page_editor_live/index_test.exs index 602bf082..9fa431bb 100644 --- a/test/beacon/live_admin/live/error_page_editor_live/index_test.exs +++ b/test/beacon/live_admin/live/error_page_editor_live/index_test.exs @@ -21,13 +21,13 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.IndexTest do test "select error page via path", %{conn: conn} do {:ok, view, _html} = live(conn, "/admin/site_a/error_pages") - assert has_element?(view, "#status-display", "Status: 404") + assert has_element?(view, "input[name='error_page[status]'][value=404]") {:ok, view, _html} = live(conn, "/admin/site_a/error_pages/404") - assert has_element?(view, "#status-display", "Status: 404") + assert has_element?(view, "input[name='error_page[status]'][value=404]") {:ok, view, _html} = live(conn, "/admin/site_a/error_pages/500") - assert has_element?(view, "#status-display", "Status: 500") + assert has_element?(view, "input[name='error_page[status]'][value=500]") end test "create a new error page", %{conn: conn} do @@ -44,7 +44,7 @@ defmodule Beacon.LiveAdmin.ErrorPageEditorLive.IndexTest do |> follow_redirect(conn, "/admin/site_a/error_pages/400") refute has_element?(view, "#create-modal") - assert has_element?(view, "#status-display", "Status: 400") + assert has_element?(view, "input[name='error_page[status]'][value=400]") end test "update an error page", %{conn: conn, another_layout: layout} do From 5bcdc1539acc5277fefcdab27bfa69de708f8052 Mon Sep 17 00:00:00 2001 From: Leandro Pereira Date: Tue, 17 Oct 2023 16:56:54 -0400 Subject: [PATCH 7/8] remove unused dep --- mix.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/mix.lock b/mix.lock index 0dd4079d..9f07c55d 100644 --- a/mix.lock +++ b/mix.lock @@ -1,7 +1,6 @@ %{ "accent": {:hex, :accent, "1.1.1", "20257356446d45078b19b91608f74669b407b39af891ee3db9ee6824d1cae19d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.3", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "6d5afa50d4886e3370e04fa501468cbaa6c4b5fe926f72ccfa844ad9e259adae"}, "beacon": {:git, "https://github.com/beaconCMS/beacon.git", "884fbf717eefc0c9fb51cbc795410e453fa50e17", []}, - "brotli": {:hex, :brotli, "0.3.2", "59cf45a399098516f1d34f70d8e010e5c9bf326659d3ef34c7cc56793339002b", [:rebar3], [], "hexpm", "9ec3ef9c753f80d0c657b4905193c55e5198f169fa1d1c044d8601d4d931a2ad"}, "castore": {:hex, :castore, "1.0.4", "ff4d0fb2e6411c0479b1d965a814ea6d00e51eb2f58697446e9c41a97d940b28", [:mix], [], "hexpm", "9418c1b8144e11656f0be99943db4caf04612e3eaecefb5dae9a2a87565584f8"}, "cc_precompiler": {:hex, :cc_precompiler, "0.1.7", "77de20ac77f0e53f20ca82c563520af0237c301a1ec3ab3bc598e8a96c7ee5d9", [:mix], [{:elixir_make, "~> 0.7.3", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2768b28bf3c2b4f788c995576b39b8cb5d47eb788526d93bd52206c1d8bf4b75"}, "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, From 69d278609f0ed58576b4cdcdab4ff0b838187c3a Mon Sep 17 00:00:00 2001 From: Leandro Pereira Date: Tue, 17 Oct 2023 16:59:22 -0400 Subject: [PATCH 8/8] update deps --- mix.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mix.lock b/mix.lock index 9f07c55d..6230b825 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,6 @@ %{ "accent": {:hex, :accent, "1.1.1", "20257356446d45078b19b91608f74669b407b39af891ee3db9ee6824d1cae19d", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:plug, "~> 1.3", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "6d5afa50d4886e3370e04fa501468cbaa6c4b5fe926f72ccfa844ad9e259adae"}, - "beacon": {:git, "https://github.com/beaconCMS/beacon.git", "884fbf717eefc0c9fb51cbc795410e453fa50e17", []}, + "beacon": {:git, "https://github.com/beaconCMS/beacon.git", "f5681121068b642a0e9cd691bce94fd1e7549c6d", []}, "castore": {:hex, :castore, "1.0.4", "ff4d0fb2e6411c0479b1d965a814ea6d00e51eb2f58697446e9c41a97d940b28", [:mix], [], "hexpm", "9418c1b8144e11656f0be99943db4caf04612e3eaecefb5dae9a2a87565584f8"}, "cc_precompiler": {:hex, :cc_precompiler, "0.1.7", "77de20ac77f0e53f20ca82c563520af0237c301a1ec3ab3bc598e8a96c7ee5d9", [:mix], [{:elixir_make, "~> 0.7.3", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "2768b28bf3c2b4f788c995576b39b8cb5d47eb788526d93bd52206c1d8bf4b75"}, "cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"}, @@ -29,16 +29,16 @@ "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, "mix_test_watch": {:hex, :mix_test_watch, "1.1.0", "330bb91c8ed271fe408c42d07e0773340a7938d8a0d281d57a14243eae9dc8c3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}], "hexpm", "52b6b1c476cbb70fd899ca5394506482f12e5f6b0d6acff9df95c7f1e0812ec3"}, "nimble_parsec": {:hex, :nimble_parsec, "1.3.1", "2c54013ecf170e249e9291ed0a62e5832f70a476c61da16f6aac6dca0189f2af", [:mix], [], "hexpm", "2682e3c0b2eb58d90c6375fc0cc30bc7be06f365bf72608804fb9cffa5e1b167"}, - "phoenix": {:hex, :phoenix, "1.7.7", "4cc501d4d823015007ba3cdd9c41ecaaf2ffb619d6fb283199fa8ddba89191e0", [: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.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "8966e15c395e5e37591b6ed0bd2ae7f48e961f0f60ac4c733f9566b519453085"}, + "phoenix": {:hex, :phoenix, "1.7.9", "9a2b873e2cb3955efdd18ad050f1818af097fa3f5fc3a6aaba666da36bdd3f02", [: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 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", "83e32da028272b4bfd076c61a964e6d2b9d988378df2f1276a0ed21b13b5e997"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.2", "b21bd01fdeffcfe2fab49e4942aa938b6d3e89e93a480d4aee58085560a0bc0d", [:mix], [{:ecto, "~> 3.5", [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", "70242edd4601d50b69273b057ecf7b684644c19ee750989fd555625ae4ce8f5d"}, - "phoenix_html": {:hex, :phoenix_html, "3.3.2", "d6ce982c6d8247d2fc0defe625255c721fb8d5f1942c5ac051f6177bffa5973f", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "44adaf8e667c1c20fb9d284b6b0fa8dc7946ce29e81ce621860aa7e96de9a11d"}, + "phoenix_html": {:hex, :phoenix_html, "3.3.3", "380b8fb45912b5638d2f1d925a3771b4516b9a78587249cabe394e0a5d579dc9", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "923ebe6fec6e2e3b3e569dfbdc6560de932cd54b000ada0208b5f45024bdd76c"}, "phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [: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", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.19.5", "6e730595e8e9b8c5da230a814e557768828fd8dfeeb90377d2d8dbb52d4ec00a", [: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.3", [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", "b2eaa0dd3cfb9bd7fb949b88217df9f25aed915e986a28ad5c8a0d054e7ca9d3"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.1", "92a37acf07afca67ac98bd326532ba8f44ad7d4bdf3e4361b03f7f02594e5ae9", [: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.3", [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]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "be494fd1215052729298b0e97d5c2ce8e719c00854b82cd8cf15c1cd7fcf6294"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, "phoenix_template": {:hex, :phoenix_template, "1.0.3", "32de561eefcefa951aead30a1f94f1b5f0379bc9e340bb5c667f65f1edfa4326", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "16f4b6588a4152f3cc057b9d0c0ba7e82ee23afa65543da535313ad8d25d8e2c"}, - "plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [: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", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"}, + "plug": {:hex, :plug, "1.15.1", "b7efd81c1a1286f13efb3f769de343236bd8b7d23b4a9f40d3002fc39ad8f74c", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "459497bd94d041d98d948054ec6c0b76feacd28eec38b219ca04c0de13c79d30"}, "plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [: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", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"}, - "plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"}, + "plug_crypto": {:hex, :plug_crypto, "2.0.0", "77515cc10af06645abbfb5e6ad7a3e9714f805ae118fa1a70205f80d2d70fe73", [:mix], [], "hexpm", "53695bae57cc4e54566d993eb01074e4d894b65a3766f1c43e2c61a1b0f45ea9"}, "postgrex": {:hex, :postgrex, "0.17.1", "01c29fd1205940ee55f7addb8f1dc25618ca63a8817e56fac4f6846fc2cddcbe", [:mix], [{: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", "14b057b488e73be2beee508fb1955d8db90d6485c6466428fe9ccf1d6692a555"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "rustler_precompiled": {:hex, :rustler_precompiled, "0.7.0", "5d0834fc06dbc76dd1034482f17b1797df0dba9b491cef8bb045fcaca94bcade", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "fdf43a6835f4e4de5bfbc4c019bfb8c46d124bd4635fefa3e20d9a2bbbec1512"},