diff --git a/lib/beacon/live_admin/content.ex b/lib/beacon/live_admin/content.ex index 4748b308..3303afd2 100644 --- a/lib/beacon/live_admin/content.ex +++ b/lib/beacon/live_admin/content.ex @@ -210,20 +210,12 @@ defmodule Beacon.LiveAdmin.Content do call(site, Beacon.Content, :create_assign_for_live_data, [live_data, attrs]) end - def get_live_data(site, path) do - call(site, Beacon.Content, :get_live_data, [site, path]) + def get_live_data(site, id) do + call(site, Beacon.Content, :get_live_data, [id]) end - def live_data_for_site(site) do - call(site, Beacon.Content, :live_data_for_site, [site]) - end - - def live_data_paths_for_site(site) do - call(site, Beacon.Content, :live_data_paths_for_site, [site]) - end - - def live_data_paths_for_site(site, opts) do - call(site, Beacon.Content, :live_data_paths_for_site, [site, opts]) + def live_data_for_site(site, opts \\ []) do + call(site, Beacon.Content, :live_data_for_site, [site, opts]) end def update_live_data_path(site, live_data, attrs) do diff --git a/lib/beacon/live_admin/live/live_data_editor_live/assigns.ex b/lib/beacon/live_admin/live/live_data_editor_live/assigns.ex index 67920f11..424bdd22 100644 --- a/lib/beacon/live_admin/live/live_data_editor_live/assigns.ex +++ b/lib/beacon/live_admin/live/live_data_editor_live/assigns.ex @@ -8,34 +8,29 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Assigns do def menu_link(_, _), do: :skip def handle_params(params, _url, socket) do - path = URI.decode_www_form(params["path"]) + %{beacon_page: %{site: site}} = socket.assigns socket = socket - |> assign(live_data: Content.get_live_data(socket.assigns.beacon_page.site, path)) + |> assign(live_data: Content.get_live_data(site, params["live_data_id"])) |> assign(unsaved_changes: false) |> assign(show_nav_modal: false) |> assign(show_create_modal: false) |> assign(show_delete_modal: false) |> assign(new_assign_form: to_form(%{"key" => ""})) |> assign(page_title: "Live Data") - |> assign_selected(params["key"]) + |> assign_selected(params["assign_id"]) |> assign_form() {:noreply, socket} end - def handle_event("select-" <> key, _, socket) do - %{live_data: %{site: site, path: path}} = socket.assigns + def handle_event("select-" <> assign_id, _, socket) do + %{live_data: %{site: site} = live_data, unsaved_changes: unsaved_changes} = socket.assigns - path = - beacon_live_admin_path( - socket, - site, - "/live_data/#{sanitize(path)}/#{sanitize(key)}" - ) + path = beacon_live_admin_path(socket, site, "/live_data/#{live_data.id}/assigns/#{assign_id}") - if socket.assigns.unsaved_changes do + if unsaved_changes do {:noreply, assign(socket, show_nav_modal: true, confirm_nav_path: path)} else {:noreply, push_redirect(socket, to: path)} @@ -94,7 +89,7 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Assigns do end def handle_event("save_changes", %{"live_data_assign" => params}, socket) do - %{selected: selected, live_data: %{site: site, path: live_data_path}} = socket.assigns + %{selected: selected, live_data: %{site: site} = live_data} = socket.assigns attrs = %{key: params["key"], value: params["value"], format: params["format"]} @@ -105,11 +100,11 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Assigns do beacon_live_admin_path( socket, site, - "/live_data/#{sanitize(live_data_path)}/#{sanitize(live_data_assign.key)}" + "/live_data/#{live_data.id}/assigns/#{live_data_assign.id}" ) socket - |> assign(live_data: Content.get_live_data(site, live_data_path)) + |> assign(live_data: Content.get_live_data(site, live_data.id)) |> assign_form() |> assign(unsaved_changes: false) |> push_patch(to: path) @@ -128,7 +123,7 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Assigns do def handle_event("submit_new", params, socket) do %{live_data: %{site: site} = live_data, selected: selected} = socket.assigns - selected = selected || %{key: nil} + selected = selected || %{id: nil} attrs = %{key: params["key"], value: "Your value here", format: :text} # TODO: handle errors @@ -137,7 +132,7 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Assigns do socket = socket |> assign(live_data: updated_live_data) - |> assign_selected(selected.key) + |> assign_selected(selected.id) {:noreply, assign(socket, show_create_modal: false)} end @@ -147,13 +142,13 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Assigns do end def handle_event("delete_confirm", _, socket) do - %{selected: selected, live_data: %{site: site, path: path}} = socket.assigns + %{selected: selected, live_data: %{site: site} = live_data} = socket.assigns {:ok, _} = Content.delete_live_data_assign(site, selected) {:noreply, push_redirect(socket, - to: beacon_live_admin_path(socket, site, "/live_data/#{sanitize(path)}") + to: beacon_live_admin_path(socket, site, "/live_data/#{live_data.id}/assigns") )} end @@ -223,7 +218,7 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Assigns do
Path:
<%= @live_data.path %>
- <.table :if={@selected} id="assigns" rows={@live_data.assigns} row_click={fn assign -> "select-#{assign.key}" end}> + <.table :if={@selected} id="assigns" rows={@live_data.assigns} row_click={fn assign -> "select-#{assign.id}" end}> <:col :let={assign} label="assign"> @<%= assign.key %> @@ -272,14 +267,19 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Assigns do end end - defp assign_selected(socket, key) do - key = URI.decode_www_form(key) - selected = Enum.find(socket.assigns.live_data.assigns, &(&1.key == key)) + defp assign_selected(socket, id) do + %{live_data: live_data} = socket.assigns + selected = Enum.find(live_data.assigns, &(&1.id == id)) if selected do assign(socket, selected: selected, changed_value: selected.value) else - path = beacon_live_admin_path(socket, socket.assigns.beacon_page.site, "/live_data") + path = + beacon_live_admin_path( + socket, + socket.assigns.beacon_page.site, + "/live_data/#{live_data.id}/assigns" + ) socket |> assign(selected: nil) @@ -306,8 +306,6 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Assigns do assign(socket, :form, to_form(changeset)) end - defp sanitize(path_or_key), do: URI.encode_www_form(path_or_key) - defp variables_available(path) do path |> String.split("/", trim: true) diff --git a/lib/beacon/live_admin/live/live_data_editor_live/index.ex b/lib/beacon/live_admin/live/live_data_editor_live/index.ex index b9199bd6..eeb9c632 100644 --- a/lib/beacon/live_admin/live/live_data_editor_live/index.ex +++ b/lib/beacon/live_admin/live/live_data_editor_live/index.ex @@ -16,9 +16,9 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Index do def handle_params(%{"query" => query}, _uri, socket) do %{beacon_page: %{site: site}} = socket.assigns - live_data_paths = Content.live_data_paths_for_site(site, query: query) + live_data_paths = Content.live_data_for_site(site, query: query) - {:noreply, assign(socket, live_data_paths: live_data_paths)} + {:noreply, assign(socket, live_data_list: live_data_paths)} end def handle_params(params, _uri, socket) do @@ -26,12 +26,12 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Index do socket = socket - |> assign(live_data_paths: Content.live_data_paths_for_site(site)) + |> assign(live_data_list: Content.live_data_for_site(site)) |> assign(show_new_path_modal: live_action == :new) |> assign(show_edit_path_modal: live_action == :edit) |> assign(show_delete_path_modal: live_action == :delete) - |> assign_edit_path_form(params["path"]) - |> assign_selected(params["path"]) + |> assign_edit_path_form(params["live_data_id"]) + |> assign_selected(params["live_data_id"]) {:noreply, socket} end @@ -50,10 +50,9 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Index do case Content.create_live_data(site, %{path: path, site: site}) do {:ok, live_data} -> socket - |> assign(live_data_paths: Content.live_data_paths_for_site(site)) + |> assign(live_data_list: Content.live_data_for_site(site)) |> push_navigate( - to: - beacon_live_admin_path(socket, site, "/live_data/#{sanitize_path(live_data.path)}") + to: beacon_live_admin_path(socket, site, "/live_data/#{live_data.id}/assigns") ) {:error, _changeset} -> @@ -65,7 +64,7 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Index do def handle_event("edit_path", params, socket) do %{beacon_page: %{site: site}, selected: selected} = socket.assigns - %{"live_data" => %{"path" => path}} = params + %{"path" => path} = params {:ok, _live_data} = Content.update_live_data_path(site, selected, path) @@ -87,17 +86,7 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Index do {:noreply, push_navigate(socket, to: path, replace: true)} end - defp assign_edit_path_form(socket, nil), do: assign(socket, edit_path_form: to_form(%{})) - - defp assign_edit_path_form(socket, path) do - form = - {%{}, %{path: :string}} - |> Ecto.Changeset.cast(%{path: path}, [:path]) - |> Ecto.Changeset.validate_required([:path]) - |> to_form(as: :live_data) - - assign(socket, edit_path_form: form) - end + defp assign_edit_path_form(socket, _id), do: assign(socket, edit_path_form: to_form(%{})) defp assign_selected(socket, nil), do: assign(socket, selected: nil) @@ -126,16 +115,16 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Index do <.main_content> - <.table id="live_data" rows={@live_data_paths} row_click={fn live_data_path -> JS.navigate(beacon_live_admin_path(@socket, @beacon_page.site, "/live_data/#{sanitize_path(live_data_path)}")) end}> - <:col :let={live_data_path} label="Path"><%= live_data_path %> - <:action :let={live_data_path}> + <.table id="live_data" rows={@live_data_list} row_click={&JS.navigate(beacon_live_admin_path(@socket, @beacon_page.site, "/live_data/#{&1.id}/assigns"))} row_id={&"live-data-table-row-#{&1.id}"}> + <:col :let={live_data} label="Path"><%= live_data.path %> + <:action :let={live_data}>
- <.link id={"edit-live-data-" <> live_data_path} navigate={beacon_live_admin_path(@socket, @beacon_page.site, "/live_data/edit/#{sanitize_path(live_data_path)}")} title="Edit live data"> + <.link id={"edit-live-data-" <> live_data.id} navigate={beacon_live_admin_path(@socket, @beacon_page.site, "/live_data/#{live_data.id}")} title="Edit live data"> Edit
<.link - patch={beacon_live_admin_path(@socket, @beacon_page.site, "/live_data/edit/#{sanitize_path(live_data_path)}")} + patch={beacon_live_admin_path(@socket, @beacon_page.site, "/live_data/#{live_data.id}")} title="Edit live data" aria-label="Edit live data" class="flex items-center justify-center w-10 h-10 group" @@ -170,8 +159,4 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.Index do """ end - - defp sanitize_path(path) do - URI.encode_www_form(path) - end end diff --git a/lib/beacon/live_admin/router.ex b/lib/beacon/live_admin/router.ex index def87121..7da8a333 100644 --- a/lib/beacon/live_admin/router.ex +++ b/lib/beacon/live_admin/router.ex @@ -153,9 +153,11 @@ defmodule Beacon.LiveAdmin.Router do # live data {"/live_data", Beacon.LiveAdmin.LiveDataEditorLive.Index, :index, %{}}, {"/live_data/new", Beacon.LiveAdmin.LiveDataEditorLive.Index, :new, %{}}, - {"/live_data/edit/:path", Beacon.LiveAdmin.LiveDataEditorLive.Index, :edit, %{}}, - {"/live_data/:path", Beacon.LiveAdmin.LiveDataEditorLive.Assigns, :assigns, %{}}, - {"/live_data/:path/:key", Beacon.LiveAdmin.LiveDataEditorLive.Assigns, :assigns, %{}}, + {"/live_data/:live_data_id", Beacon.LiveAdmin.LiveDataEditorLive.Index, :edit, %{}}, + {"/live_data/:live_data_id/assigns", Beacon.LiveAdmin.LiveDataEditorLive.Assigns, :assigns, + %{}}, + {"/live_data/:live_data_id/assigns/:assign_id", Beacon.LiveAdmin.LiveDataEditorLive.Assigns, + :assigns, %{}}, # media library {"/media_library", Beacon.LiveAdmin.MediaLibraryLive.Index, :index, %{}}, {"/media_library/upload", Beacon.LiveAdmin.MediaLibraryLive.Index, :upload, %{}}, diff --git a/mix.lock b/mix.lock index b0673c5a..078e843e 100644 --- a/mix.lock +++ b/mix.lock @@ -1,7 +1,7 @@ %{ "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", "963491986df5988a180e6fa81f705f25428dd377", []}, - "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"}, + "beacon": {:git, "https://github.com/beaconCMS/beacon.git", "0a2260e15ba57fd867489d85254671db74a0d442", []}, + "castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"}, "cc_precompiler": {:hex, :cc_precompiler, "0.1.9", "e8d3364f310da6ce6463c3dd20cf90ae7bbecbf6c5203b98bf9b48035592649b", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "9dcab3d0f3038621f1601f13539e7a9ee99843862e66ad62827b0c42b2f58a54"}, "cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, "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"}, diff --git a/test/beacon/live_admin/live/live_data_editor_live/assigns_test.exs b/test/beacon/live_admin/live/live_data_editor_live/assigns_test.exs index f1430a33..47a6f0b4 100644 --- a/test/beacon/live_admin/live/live_data_editor_live/assigns_test.exs +++ b/test/beacon/live_admin/live/live_data_editor_live/assigns_test.exs @@ -10,14 +10,14 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.AssignsTest do rpc(node1(), Beacon.Repo, :delete_all, [Beacon.Content.LiveDataAssign, [log: false]]) end) - page_fixture() + page = page_fixture() live_data = live_data_fixture(node1(), path: "/home") - [live_data: live_data] + [page: page, live_data: live_data] end - test "create new assign", %{conn: conn} do - {:ok, view, _html} = live(conn, "/admin/site_a/live_data/%2Fhome") + test "create new assign", %{conn: conn, live_data: live_data} do + {:ok, view, _html} = live(conn, "/admin/site_a/live_data/#{live_data.id}/assigns") view |> element("button", "New Live Data Assign") @@ -27,28 +27,29 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.AssignsTest do |> form("#new-assign-form", %{"key" => "valid?"}) |> render_submit() - {:ok, view, html} = live(conn, "/admin/site_a/live_data/%2Fhome/valid%3F") + assert render(view) =~ "@valid?" + end - assert html =~ "@valid?" - assert has_element?(view, ~S|input[value="valid?"]|) + test "nonexistent assign redirects to root live data page", %{conn: conn, live_data: live_data} do + assert {:error, {:live_redirect, %{to: "/admin/site_a/live_data/#{live_data.id}/assigns"}}} == + live(conn, "/admin/site_a/live_data/#{live_data.id}/assigns/invalid-id") end test "edit existing assign", %{conn: conn, live_data: live_data} do - live_data_assign_fixture(node1(), live_data: live_data) - {:ok, view, _html} = live(conn, "/admin/site_a/live_data/%2Fhome/sum") + lda = live_data_assign_fixture(node1(), live_data: live_data) + {:ok, view, _html} = live(conn, "/admin/site_a/live_data/#{live_data.id}/assigns/#{lda.id}") - html = - view - |> form("#edit-assign-form", %{"live_data_assign" => %{"key" => "new_key"}}) - |> render_submit() + view + |> form("#edit-assign-form", %{"live_data_assign" => %{"key" => "new_key"}}) + |> render_submit() - assert html =~ "@new_key" + assert render(view) =~ "@new_key" assert has_element?(view, ~S|input[value="new_key"]|) end test "delete existing assign", %{conn: conn, live_data: live_data} do - live_data_assign_fixture(node1(), live_data: live_data) - {:ok, view, _html} = live(conn, "/admin/site_a/live_data/%2Fhome/sum") + lda = live_data_assign_fixture(node1(), live_data: live_data) + {:ok, view, _html} = live(conn, "/admin/site_a/live_data/#{live_data.id}/assigns/#{lda.id}") view |> element("button", "Delete") @@ -60,6 +61,6 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.AssignsTest do |> render_click() |> follow_redirect(conn) - refute html =~ "@sum" + refute html =~ "@#{lda.key}" end end diff --git a/test/beacon/live_admin/live/live_data_editor_live/index_test.exs b/test/beacon/live_admin/live/live_data_editor_live/index_test.exs index 417e3627..d7521de5 100644 --- a/test/beacon/live_admin/live/live_data_editor_live/index_test.exs +++ b/test/beacon/live_admin/live/live_data_editor_live/index_test.exs @@ -9,37 +9,37 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.IndexTest do rpc(node1(), Beacon.Repo, :delete_all, [Beacon.Content.LiveData, [log: false]]) end) - page_fixture() - live_data_fixture(node1(), path: "/testpages/:page_id") - live_data_fixture(node1(), path: "/testobjects/:object_id") + page = page_fixture() + ld1 = live_data_fixture(node1(), path: "/testpages/:page_id") + ld2 = live_data_fixture(node1(), path: "/testobjects/:object_id") - :ok + [page: page, live_data: [ld1, ld2]] end - test "display header and all live data paths", %{conn: conn} do + test "display header and all live data paths", %{conn: conn, live_data: [ld1, ld2]} do {:ok, view, html} = live(conn, "/admin/site_a/live_data") assert assert has_element?(view, "#header-page-title", "Live Data") - assert html =~ "/testpages/:page_id" - assert html =~ "/testobjects/:object_id" + assert html =~ ld1.path + assert html =~ ld2.path end - test "search paths", %{conn: conn} do + test "search paths", %{conn: conn, live_data: [ld1, ld2]} do {:ok, view, _html} = live(conn, "/admin/site_a/live_data") view |> form("#live-data-path-search") - |> render_change(%{"search" => %{"query" => "pages"}}) + |> render_change(%{"search" => %{"query" => ld1.path}}) - assert render(view) =~ "/testpages/:page_id" - refute render(view) =~ "/testobjects/:object_id" + assert has_element?(view, "#live-data-table-row-#{ld1.id}") + refute has_element?(view, "#live-data-table-row-#{ld2.id}") view |> form("#live-data-path-search") - |> render_change(%{"search" => %{"query" => "objects"}}) + |> render_change(%{"search" => %{"query" => ld2.path}}) - refute render(view) =~ "/testpages/:page_id" - assert render(view) =~ "/testobjects/:object_id" + refute has_element?(view, "#live-data-table-row-#{ld1.id}") + assert has_element?(view, "#live-data-table-row-#{ld2.id}") end test "create new path", %{conn: conn} do @@ -53,22 +53,24 @@ defmodule Beacon.LiveAdmin.LiveDataEditorLive.IndexTest do view |> form("#new-path-form") |> render_submit(%{"path" => "/my/fun/path"}) - |> follow_redirect(conn, "/admin/site_a/live_data/%2Fmy%2Ffun%2Fpath") + |> follow_redirect(conn) assert render(view) =~ "/my/fun/path" end - test "edit existing path", %{conn: conn} do - {:ok, view, _html} = live(conn, "/admin/site_a/live_data/edit/%2Ftestpages%2F%3Apage_id") + test "edit existing path", %{conn: conn, live_data: [ld1, _ld2]} do + {:ok, view, _html} = live(conn, "/admin/site_a/live_data/#{ld1.id}") + + new_path = "/testposts/:post_id" {:ok, _view, html} = view - |> form("#edit-path-form", live_data: %{path: "/testposts/:post_id"}) + |> form("#edit-path-form", path: new_path) |> render_submit() |> follow_redirect(conn, "/admin/site_a/live_data") - assert html =~ "/testposts/:post_id" - refute html =~ "/testpages/:page_id" + assert html =~ new_path + refute html =~ ld1.path end test "raises when missing beacon_live_admin_url in the session" do diff --git a/test/support/fixtures.ex b/test/support/fixtures.ex index 0e700b6a..0f7f9fd7 100644 --- a/test/support/fixtures.ex +++ b/test/support/fixtures.ex @@ -90,9 +90,7 @@ defmodule Beacon.LiveAdmin.Fixtures do Enum.into(attrs, %{ site: "site_a", path: "/foo/:id", - assign: "bar", - format: :elixir, - code: "id" + format: :elixir }) rpc(node, Beacon.Content, :create_live_data!, [attrs]) @@ -108,6 +106,8 @@ defmodule Beacon.LiveAdmin.Fixtures do value: "1 + 1" }) - rpc(node, Beacon.Content, :create_assign_for_live_data, [live_data, attrs]) + {:ok, live_data} = rpc(node, Beacon.Content, :create_assign_for_live_data, [live_data, attrs]) + + Enum.find(live_data.assigns, &(&1.key == attrs.key)) end end