diff --git a/.credo.exs b/.credo.exs index 8b1cb6763..175c09e4c 100644 --- a/.credo.exs +++ b/.credo.exs @@ -1,4 +1,11 @@ +alias_usage_defaults = Credo.Check.Design.AliasUsage.param_defaults() + overwrite_checks = [ + {Credo.Check.Design.AliasUsage, + excluded_namespaces: alias_usage_defaults[:excluded_namespaces] ++ ["Backpex.Fields"], + excluded_lastnames: alias_usage_defaults[:excluded_lastnames] ++ ["Type"], + if_nested_deeper_than: 2, + if_called_more_often_than: 1}, {Credo.Check.Design.TagTODO, false}, {Credo.Check.Readability.AliasAs, false}, {Credo.Check.Readability.OnePipePerLine, false}, diff --git a/.formatter.exs b/.formatter.exs index a80b7aaea..12a89951f 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -9,10 +9,5 @@ locals_without_parens = [ plugins: [Phoenix.LiveView.HTMLFormatter, Quokka], inputs: ["*.{heex,ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{heex,ex,exs}"], locals_without_parens: locals_without_parens, - export: [locals_without_parens: locals_without_parens], - quokka: [ - exclude: [ - :module_directives - ] - ] + export: [locals_without_parens: locals_without_parens] ] diff --git a/.gitignore b/.gitignore index a644634a1..2cb7a7b32 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,10 @@ - # System / Docker .vscode .bash_history .env /.elixir_ls/ .DS_Store +.claude/settings.local.json # Phoenix /_build/ @@ -19,4 +19,3 @@ backpex-*.tar /priv/static/cache_manifest.json npm-debug.log /node_modules - diff --git a/demo/.formatter.exs b/demo/.formatter.exs index 131671b5b..59162323c 100644 --- a/demo/.formatter.exs +++ b/demo/.formatter.exs @@ -3,10 +3,5 @@ import_deps: [:ecto, :phoenix, :backpex], plugins: [Phoenix.LiveView.HTMLFormatter, Quokka], inputs: ["*.{heex,ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{heex,ex,exs}"], - subdirectories: ["priv/*/migrations"], - quokka: [ - exclude: [ - :module_directives - ] - ] + subdirectories: ["priv/*/migrations"] ] diff --git a/demo/config/runtime.exs b/demo/config/runtime.exs index 443d03fe3..a0b12ad79 100644 --- a/demo/config/runtime.exs +++ b/demo/config/runtime.exs @@ -1,6 +1,6 @@ import Config -import System, only: [get_env: 1, get_env: 2, fetch_env!: 1] import String, only: [to_integer: 1, to_atom: 1, to_existing_atom: 1] +import System, only: [get_env: 1, get_env: 2, fetch_env!: 1] config :demo, Demo.Repo, hostname: get_env("DB_HOSTNAME", "postgres"), diff --git a/demo/lib/demo/category.ex b/demo/lib/demo/category.ex index f0b4d1092..8b8723e5d 100644 --- a/demo/lib/demo/category.ex +++ b/demo/lib/demo/category.ex @@ -2,6 +2,7 @@ defmodule Demo.Category do @moduledoc false use Ecto.Schema + import Ecto.Changeset @primary_key {:id, :binary_id, autogenerate: true} diff --git a/demo/lib/demo/film_review.ex b/demo/lib/demo/film_review.ex index 9fefaf3a7..4403f5c6f 100644 --- a/demo/lib/demo/film_review.ex +++ b/demo/lib/demo/film_review.ex @@ -2,6 +2,7 @@ defmodule Demo.FilmReview do @moduledoc false use Ecto.Schema + import Ecto.Changeset @primary_key {:id, :binary_id, autogenerate: true} diff --git a/demo/lib/demo/post.ex b/demo/lib/demo/post.ex index e3b42e365..d2030abf0 100644 --- a/demo/lib/demo/post.ex +++ b/demo/lib/demo/post.ex @@ -2,6 +2,7 @@ defmodule Demo.Post do @moduledoc false use Ecto.Schema + import Ecto.Changeset @primary_key {:id, :binary_id, autogenerate: true} diff --git a/demo/lib/demo/product.ex b/demo/lib/demo/product.ex index 7baa1bfad..0787212a6 100644 --- a/demo/lib/demo/product.ex +++ b/demo/lib/demo/product.ex @@ -30,12 +30,12 @@ defmodule Demo.Product do product |> cast(attrs, @required_fields ++ @optional_fields) |> cast_assoc(:suppliers, - with: &Demo.Supplier.changeset/2, + with: &Supplier.changeset/2, sort_param: :suppliers_order, drop_param: :suppliers_delete ) |> cast_assoc(:short_links, - with: &Demo.ShortLink.changeset/2, + with: &ShortLink.changeset/2, sort_param: :short_links_order, drop_param: :short_links_delete ) diff --git a/demo/lib/demo/supplier.ex b/demo/lib/demo/supplier.ex index e749c31b9..995804739 100644 --- a/demo/lib/demo/supplier.ex +++ b/demo/lib/demo/supplier.ex @@ -4,6 +4,8 @@ defmodule Demo.Supplier do import Ecto.Changeset + alias Demo.Product + @primary_key {:id, :binary_id, autogenerate: true} @countries ["Austria", "France", "Germany", "Italy", "Spain", "Switzerland"] @@ -18,7 +20,7 @@ defmodule Demo.Supplier do field :minimum_order, Money.Ecto.Amount.Type field :preferred, :boolean, default: false - belongs_to :product, Demo.Product, type: :binary_id + belongs_to :product, Product, type: :binary_id timestamps() end diff --git a/demo/lib/demo/tag.ex b/demo/lib/demo/tag.ex index aa6331e48..df92e5a62 100644 --- a/demo/lib/demo/tag.ex +++ b/demo/lib/demo/tag.ex @@ -2,6 +2,7 @@ defmodule Demo.Tag do @moduledoc false use Ecto.Schema + import Ecto.Changeset @primary_key {:id, :binary_id, autogenerate: true} diff --git a/demo/lib/demo_web.ex b/demo/lib/demo_web.ex index 60ef46527..7a74117a8 100644 --- a/demo/lib/demo_web.ex +++ b/demo/lib/demo_web.ex @@ -23,10 +23,9 @@ defmodule DemoWeb do quote do use Phoenix.Router, helpers: false - # Import common connection and controller functions to use in pipelines - import Plug.Conn import Phoenix.Controller import Phoenix.LiveView.Router + import Plug.Conn end end @@ -39,7 +38,6 @@ defmodule DemoWeb do def controller do quote do use Phoenix.Controller, formats: [:html, :json] - use Gettext, backend: DemoWeb.Gettext import Plug.Conn @@ -68,11 +66,9 @@ defmodule DemoWeb do quote do use Phoenix.Component - # Import convenience functions from controllers import Phoenix.Controller, only: [get_csrf_token: 0, view_module: 1, view_template: 1] - # Include general helpers for rendering HTML unquote(html_helpers()) end end @@ -80,16 +76,13 @@ defmodule DemoWeb do defp html_helpers do quote do use Gettext, backend: DemoWeb.Gettext - # HTML escaping functionality - import Phoenix.HTML - # Core UI components and translation + import DemoWeb.CoreComponents + import Phoenix.HTML - # Common modules used in templates alias DemoWeb.Layouts alias Phoenix.LiveView.JS - # Routes generation with the ~p sigil unquote(verified_routes()) end end diff --git a/demo/lib/demo_web/endpoint.ex b/demo/lib/demo_web/endpoint.ex index f5f2380d2..a201ea583 100644 --- a/demo/lib/demo_web/endpoint.ex +++ b/demo/lib/demo_web/endpoint.ex @@ -4,13 +4,17 @@ defmodule DemoWeb.Endpoint do # The session will be stored in the cookie and signed, # this means its contents can be read but not tampered with. # Set :encryption_salt if you would also like to encrypt it. + alias Phoenix.Ecto.CheckRepoStatus + alias Phoenix.LiveDashboard.RequestLogger + alias Phoenix.LiveView.Socket + @session_options [ store: :cookie, key: "_demo_key", signing_salt: "szYoVHQC" ] - socket "/live", Phoenix.LiveView.Socket, + socket "/live", Socket, websocket: [ connect_info: [:peer_data, :uri, :user_agent, session: @session_options] ] @@ -35,10 +39,10 @@ defmodule DemoWeb.Endpoint do socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket plug Phoenix.LiveReloader plug Phoenix.CodeReloader - plug Phoenix.Ecto.CheckRepoStatus, otp_app: :demo + plug CheckRepoStatus, otp_app: :demo end - plug Phoenix.LiveDashboard.RequestLogger, + plug RequestLogger, param_key: "request_logger", cookie_key: "request_logger" diff --git a/demo/lib/demo_web/filters/post_category_select.ex b/demo/lib/demo_web/filters/post_category_select.ex index 3fb9ed3e3..23a2f1012 100644 --- a/demo/lib/demo_web/filters/post_category_select.ex +++ b/demo/lib/demo_web/filters/post_category_select.ex @@ -5,6 +5,7 @@ defmodule DemoWeb.Filters.PostCategorySelect do use Backpex.Filters.Select + alias Backpex.Filters.Select alias Demo.Category alias Demo.Post alias Demo.Repo @@ -12,10 +13,10 @@ defmodule DemoWeb.Filters.PostCategorySelect do @impl Backpex.Filter def label, do: "Category" - @impl Backpex.Filters.Select + @impl Select def prompt, do: "Select category ..." - @impl Backpex.Filters.Select + @impl Select def options(_assigns) do query = from p in Post, diff --git a/demo/lib/demo_web/filters/post_published.ex b/demo/lib/demo_web/filters/post_published.ex index 3b38a8fe9..affaff14e 100644 --- a/demo/lib/demo_web/filters/post_published.ex +++ b/demo/lib/demo_web/filters/post_published.ex @@ -5,10 +5,12 @@ defmodule DemoWeb.Filters.PostPublished do use Backpex.Filters.Boolean + alias Backpex.Filters.Boolean + @impl Backpex.Filter def label, do: "Published?" - @impl Backpex.Filters.Boolean + @impl Boolean def options(_assigns) do [ %{ diff --git a/demo/lib/demo_web/filters/post_user_multi_select.ex b/demo/lib/demo_web/filters/post_user_multi_select.ex index c48e411fc..1b71a19e3 100644 --- a/demo/lib/demo_web/filters/post_user_multi_select.ex +++ b/demo/lib/demo_web/filters/post_user_multi_select.ex @@ -5,16 +5,17 @@ defmodule DemoWeb.Filters.PostUserMultiSelect do use Backpex.Filters.MultiSelect + alias Backpex.Filters.Select alias Demo.Post alias Demo.Repo @impl Backpex.Filter def label, do: "Users" - @impl Backpex.Filters.Select + @impl Select def prompt, do: "Select users ..." - @impl Backpex.Filters.Select + @impl Select def options(_assigns) do query = from p in Post, diff --git a/demo/lib/demo_web/item_actions/user_soft_delete.ex b/demo/lib/demo_web/item_actions/user_soft_delete.ex index da02b6c6c..0ccb3bd12 100644 --- a/demo/lib/demo_web/item_actions/user_soft_delete.ex +++ b/demo/lib/demo_web/item_actions/user_soft_delete.ex @@ -4,7 +4,9 @@ defmodule DemoWeb.ItemActions.UserSoftDelete do use BackpexWeb, :item_action import Ecto.Changeset + alias Backpex.ItemActions.Delete + require Logger @impl Backpex.ItemAction diff --git a/demo/lib/demo_web/live/post_live.ex b/demo/lib/demo_web/live/post_live.ex index 75d89b9c5..f34b7683f 100644 --- a/demo/lib/demo_web/live/post_live.ex +++ b/demo/lib/demo_web/live/post_live.ex @@ -11,28 +11,40 @@ defmodule DemoWeb.PostLive do import Ecto.Query, warn: false - @impl Backpex.LiveResource - def layout(_assigns), do: {DemoWeb.Layouts, :admin} + alias Backpex.LiveResource + alias Backpex.Metrics.Value + alias DemoWeb.CategoryLive + alias DemoWeb.Filters.DateTimeRange + alias DemoWeb.Filters.PostCategorySelect + alias DemoWeb.Filters.PostLikeRange + alias DemoWeb.Filters.PostPublished + alias DemoWeb.Filters.PostUserMultiSelect + alias DemoWeb.Layouts + alias DemoWeb.TagLive + alias DemoWeb.UserLive - @impl Backpex.LiveResource + @impl LiveResource + def layout(_assigns), do: {Layouts, :admin} + + @impl LiveResource def singular_name, do: "Post" - @impl Backpex.LiveResource + @impl LiveResource def plural_name, do: "Posts" - @impl Backpex.LiveResource + @impl LiveResource def filters do [ category_id: %{ - module: DemoWeb.Filters.PostCategorySelect, + module: PostCategorySelect, label: "Category" }, user_id: %{ - module: DemoWeb.Filters.PostUserMultiSelect, + module: PostUserMultiSelect, label: "Users" }, likes: %{ - module: DemoWeb.Filters.PostLikeRange, + module: PostLikeRange, label: "Likes", presets: [ %{ @@ -46,7 +58,7 @@ defmodule DemoWeb.PostLive do ] }, inserted_at: %{ - module: DemoWeb.Filters.DateTimeRange, + module: DateTimeRange, label: "Created at", presets: [ %{ @@ -79,7 +91,7 @@ defmodule DemoWeb.PostLive do ] }, published: %{ - module: DemoWeb.Filters.PostPublished, + module: PostPublished, label: "Published?", default: ["published"], presets: [ @@ -100,7 +112,7 @@ defmodule DemoWeb.PostLive do ] end - @impl Backpex.LiveResource + @impl LiveResource def fields do [ title: %{ @@ -166,14 +178,14 @@ defmodule DemoWeb.PostLive do end, index_editable: true, searchable: true, - live_resource: DemoWeb.UserLive + live_resource: UserLive }, category: %{ module: Backpex.Fields.BelongsTo, label: "Category", display_field: :name, searchable: true, - live_resource: DemoWeb.CategoryLive, + live_resource: CategoryLive, custom_alias: :custom_category }, tags: %{ @@ -181,7 +193,7 @@ defmodule DemoWeb.PostLive do label: "Tags", orderable: false, display_field: :name, - live_resource: DemoWeb.TagLive + live_resource: TagLive }, inserted_at: %{ module: Backpex.Fields.DateTime, @@ -191,11 +203,11 @@ defmodule DemoWeb.PostLive do ] end - @impl Backpex.LiveResource + @impl LiveResource def metrics do [ total_likes: %{ - module: Backpex.Metrics.Value, + module: Value, label: "Total likes", class: "lg:w-1/4", select: dynamic([p], sum(p.likes)), @@ -204,7 +216,7 @@ defmodule DemoWeb.PostLive do end }, published_posts: %{ - module: Backpex.Metrics.Value, + module: Value, label: "Published Posts", class: "lg:w-1/4", select: dynamic([p], count(fragment("CASE WHEN ? = TRUE THEN 1 ELSE NULL END", p.published))), diff --git a/demo/lib/demo_web/live/product_live.ex b/demo/lib/demo_web/live/product_live.ex index a962e1b0f..bf3e074f6 100644 --- a/demo/lib/demo_web/live/product_live.ex +++ b/demo/lib/demo_web/live/product_live.ex @@ -9,26 +9,35 @@ defmodule DemoWeb.ProductLive do import Ecto.Query, warn: false - @impl Backpex.LiveResource - def layout(_assigns), do: {DemoWeb.Layouts, :admin} - - @impl Backpex.LiveResource + alias Backpex.LiveResource + alias Backpex.Metrics.Value + alias Demo.Supplier + alias DemoWeb.Endpoint + alias DemoWeb.Filters.ProductQuantityRange + alias DemoWeb.Layouts + alias DemoWeb.ShortLinkLive + alias Phoenix.VerifiedRoutes + + @impl LiveResource + def layout(_assigns), do: {Layouts, :admin} + + @impl LiveResource def singular_name, do: "Product" - @impl Backpex.LiveResource + @impl LiveResource def plural_name, do: "Products" - @impl Backpex.LiveResource + @impl LiveResource def filters do [ quantity: %{ - module: DemoWeb.Filters.ProductQuantityRange, + module: ProductQuantityRange, label: "QTY" } ] end - @impl Backpex.LiveResource + @impl LiveResource def fields do [ images: %{ @@ -105,7 +114,7 @@ defmodule DemoWeb.ProductLive do module: Backpex.Fields.Select, label: "Country", prompt: "—", - options: Demo.Supplier.countries() + options: Supplier.countries() }, contract_date: %{ module: Backpex.Fields.Date, @@ -126,7 +135,7 @@ defmodule DemoWeb.ProductLive do label: "Short Links", type: :assoc, except: [:index], - live_resource: DemoWeb.ShortLinkLive, + live_resource: ShortLinkLive, child_fields: [ short_key: %{ module: Backpex.Fields.Text, @@ -141,11 +150,11 @@ defmodule DemoWeb.ProductLive do ] end - @impl Backpex.LiveResource + @impl LiveResource def metrics do [ total_quantity: %{ - module: Backpex.Metrics.Value, + module: Value, label: "In Stock", class: "w-1/3", select: dynamic([i], sum(i.quantity)), @@ -196,7 +205,7 @@ defmodule DemoWeb.ProductLive do defp file_url(file_name) do static_path = Path.join([upload_dir(), file_name]) - Phoenix.VerifiedRoutes.static_url(DemoWeb.Endpoint, "/" <> static_path) + VerifiedRoutes.static_url(Endpoint, "/" <> static_path) end defp file_name(entry) do diff --git a/demo/lib/demo_web/live/user_live.ex b/demo/lib/demo_web/live/user_live.ex index 3dea7f29c..ad9d84423 100644 --- a/demo/lib/demo_web/live/user_live.ex +++ b/demo/lib/demo_web/live/user_live.ex @@ -12,6 +12,8 @@ defmodule DemoWeb.UserLive do import Ecto.Query, warn: false + alias Backpex.Metrics.Value + @impl Backpex.LiveResource def layout(_assigns), do: {DemoWeb.Layouts, :admin} @@ -212,7 +214,7 @@ defmodule DemoWeb.UserLive do def metrics do [ min_age: %{ - module: Backpex.Metrics.Value, + module: Value, label: "Min age", class: "w-full lg:w-1/3", select: dynamic([u], min(u.age)), @@ -221,7 +223,7 @@ defmodule DemoWeb.UserLive do end }, max_age: %{ - module: Backpex.Metrics.Value, + module: Value, label: "Max age", class: "w-full lg:w-1/3", select: dynamic([u], max(u.age)), diff --git a/demo/lib/demo_web/telemetry.ex b/demo/lib/demo_web/telemetry.ex index f4d374552..df83eb03e 100644 --- a/demo/lib/demo_web/telemetry.ex +++ b/demo/lib/demo_web/telemetry.ex @@ -2,6 +2,7 @@ defmodule DemoWeb.Telemetry do @moduledoc false use Supervisor + import Telemetry.Metrics def start_link(arg) do diff --git a/demo/test/demo_web/live/address/delete_item_action_live_test.exs b/demo/test/demo_web/live/address/delete_item_action_live_test.exs index 2871c14f3..0af708fa9 100644 --- a/demo/test/demo_web/live/address/delete_item_action_live_test.exs +++ b/demo/test/demo_web/live/address/delete_item_action_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Address.DeleteItemActionLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "delete item action on index view" do test "deletes item successfully", %{conn: conn} do diff --git a/demo/test/demo_web/live/address/edit_item_action_live_test.exs b/demo/test/demo_web/live/address/edit_item_action_live_test.exs index b5d499f38..066f04574 100644 --- a/demo/test/demo_web/live/address/edit_item_action_live_test.exs +++ b/demo/test/demo_web/live/address/edit_item_action_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Address.EditItemActionLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "edit item action on index view" do test "redirects to index view", %{conn: conn} do diff --git a/demo/test/demo_web/live/address/index_live_test.exs b/demo/test/demo_web/live/address/index_live_test.exs index 97ae49940..22b8da6dc 100644 --- a/demo/test/demo_web/live/address/index_live_test.exs +++ b/demo/test/demo_web/live/address/index_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Address.IndexLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "addresses live resource index" do test "is rendered", %{conn: conn} do diff --git a/demo/test/demo_web/live/category/delete_item_action_live_test.exs b/demo/test/demo_web/live/category/delete_item_action_live_test.exs index e49a73c40..b5b08d0fb 100644 --- a/demo/test/demo_web/live/category/delete_item_action_live_test.exs +++ b/demo/test/demo_web/live/category/delete_item_action_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Category.DeleteItemActionLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "delete item action on index view" do test "deletes item successfully", %{conn: conn} do diff --git a/demo/test/demo_web/live/category/edit_item_action_live_test.exs b/demo/test/demo_web/live/category/edit_item_action_live_test.exs index 925099259..e090705ed 100644 --- a/demo/test/demo_web/live/category/edit_item_action_live_test.exs +++ b/demo/test/demo_web/live/category/edit_item_action_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Category.EditItemActionLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "edit item action on index view" do test "redirects to index view", %{conn: conn} do diff --git a/demo/test/demo_web/live/category/index_live_test.exs b/demo/test/demo_web/live/category/index_live_test.exs index 83ef14f18..e7425ccef 100644 --- a/demo/test/demo_web/live/category/index_live_test.exs +++ b/demo/test/demo_web/live/category/index_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Category.IndexLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "categories live resource index" do test "is rendered", %{conn: conn} do diff --git a/demo/test/demo_web/live/post/index_live_test.exs b/demo/test/demo_web/live/post/index_live_test.exs index f0fe137ef..b246b39e3 100644 --- a/demo/test/demo_web/live/post/index_live_test.exs +++ b/demo/test/demo_web/live/post/index_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Post.IndexLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "posts live resource index" do test "is rendered", %{conn: conn} do diff --git a/demo/test/demo_web/live/product/delete_item_action_live_test.exs b/demo/test/demo_web/live/product/delete_item_action_live_test.exs index 4a4359fbf..e95c4030f 100644 --- a/demo/test/demo_web/live/product/delete_item_action_live_test.exs +++ b/demo/test/demo_web/live/product/delete_item_action_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Product.DeleteItemActionLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "delete item action on index view" do test "deletes item successfully", %{conn: conn} do diff --git a/demo/test/demo_web/live/product/edit_item_action_live_test.exs b/demo/test/demo_web/live/product/edit_item_action_live_test.exs index 36c0ec3cf..ba84a0f31 100644 --- a/demo/test/demo_web/live/product/edit_item_action_live_test.exs +++ b/demo/test/demo_web/live/product/edit_item_action_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Product.EditItemActionLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "edit item action on index view" do test "redirects to index view", %{conn: conn} do diff --git a/demo/test/demo_web/live/product/index_live_test.exs b/demo/test/demo_web/live/product/index_live_test.exs index e481474dd..b70a00dcf 100644 --- a/demo/test/demo_web/live/product/index_live_test.exs +++ b/demo/test/demo_web/live/product/index_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Product.IndexLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "products live resource index" do test "is rendered", %{conn: conn} do diff --git a/demo/test/demo_web/live/tag/delete_item_action_live_test.exs b/demo/test/demo_web/live/tag/delete_item_action_live_test.exs index f32ff9e17..976439774 100644 --- a/demo/test/demo_web/live/tag/delete_item_action_live_test.exs +++ b/demo/test/demo_web/live/tag/delete_item_action_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Tag.DeleteItemActionLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "delete item action on index view" do test "deletes item successfully", %{conn: conn} do diff --git a/demo/test/demo_web/live/tag/edit_item_action_live_test.exs b/demo/test/demo_web/live/tag/edit_item_action_live_test.exs index cdcc1bd28..c54db8196 100644 --- a/demo/test/demo_web/live/tag/edit_item_action_live_test.exs +++ b/demo/test/demo_web/live/tag/edit_item_action_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Tag.EditItemActionLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "edit item action on index view" do test "redirects to index view", %{conn: conn} do diff --git a/demo/test/demo_web/live/tag/index_live_test.exs b/demo/test/demo_web/live/tag/index_live_test.exs index ce7831bf8..45c6c15e0 100644 --- a/demo/test/demo_web/live/tag/index_live_test.exs +++ b/demo/test/demo_web/live/tag/index_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.Tag.IndexLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "tags live resource index" do test "is rendered", %{conn: conn} do diff --git a/demo/test/demo_web/live/user/index_live_test.exs b/demo/test/demo_web/live/user/index_live_test.exs index c9d450de0..917564a47 100644 --- a/demo/test/demo_web/live/user/index_live_test.exs +++ b/demo/test/demo_web/live/user/index_live_test.exs @@ -2,8 +2,8 @@ defmodule DemoWeb.Live.User.IndexLiveTest do use DemoWeb.ConnCase, async: false import Demo.EctoFactory - import Phoenix.LiveViewTest import Demo.Support.LiveResourceTests + import Phoenix.LiveViewTest describe "users live resource index" do test "is rendered", %{conn: conn} do diff --git a/demo/test/support/conn_case.ex b/demo/test/support/conn_case.ex index b3a037840..403a79a4a 100644 --- a/demo/test/support/conn_case.ex +++ b/demo/test/support/conn_case.ex @@ -19,17 +19,14 @@ defmodule DemoWeb.ConnCase do using do quote do - # The default endpoint for testing - @endpoint DemoWeb.Endpoint - use DemoWeb, :verified_routes + import DemoWeb.ConnCase + import Phoenix.ConnTest import PhoenixTest - - # Import conveniences for testing with connections import Plug.Conn - import Phoenix.ConnTest - import DemoWeb.ConnCase + + @endpoint DemoWeb.Endpoint end end diff --git a/demo/test/support/data_case.ex b/demo/test/support/data_case.ex index f7909cd25..e100791d3 100644 --- a/demo/test/support/data_case.ex +++ b/demo/test/support/data_case.ex @@ -20,12 +20,12 @@ defmodule Demo.DataCase do using do quote do - alias Demo.Repo - + import Demo.DataCase import Ecto import Ecto.Changeset import Ecto.Query - import Demo.DataCase + + alias Demo.Repo end end diff --git a/lib/backpex/adapters/ecto.ex b/lib/backpex/adapters/ecto.ex index be73dd28a..9447cdb92 100644 --- a/lib/backpex/adapters/ecto.ex +++ b/lib/backpex/adapters/ecto.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Adapters.Ecto do @config_schema [ repo: [ diff --git a/lib/backpex/field.ex b/lib/backpex/field.ex index 8c1eae8a6..b73072605 100644 --- a/lib/backpex/field.ex +++ b/lib/backpex/field.ex @@ -1,4 +1,5 @@ # credo:disable-for-this-file Credo.Check.Refactor.CyclomaticComplexity +# quokka:skip-module-directive-reordering defmodule Backpex.Field do @config_schema [ module: [ @@ -141,20 +142,23 @@ defmodule Backpex.Field do """ import Phoenix.Component, only: [assign: 3] + alias Phoenix.LiveView.Rendered + alias Phoenix.LiveView.Socket + @doc """ Will be used on index and show views to render a value from the provided item. This has to be a heex template. """ - @callback render_value(assigns :: map()) :: %Phoenix.LiveView.Rendered{} + @callback render_value(assigns :: map()) :: %Rendered{} @doc """ Will be used on edit views to render a form for the value of the provided item. This has to be a heex template. """ - @callback render_form(assigns :: map()) :: %Phoenix.LiveView.Rendered{} + @callback render_form(assigns :: map()) :: %Rendered{} @doc """ Used to render form on index to support index editable. """ - @callback render_index_form(assigns :: map()) :: %Phoenix.LiveView.Rendered{} + @callback render_index_form(assigns :: map()) :: %Rendered{} @doc """ The field to be displayed on index views. In most cases this is the name / key configured in the corresponding field definition. @@ -176,15 +180,15 @@ defmodule Backpex.Field do @doc """ This function will be called in the `FormComponent` and may be used to assign uploads. """ - @callback assign_uploads(field :: tuple(), socket :: Phoenix.LiveView.Socket.t()) :: - Phoenix.LiveView.Socket.t() + @callback assign_uploads(field :: tuple(), socket :: Socket.t()) :: + Socket.t() @doc """ This function is called before the changeset function is called. This allows fields to modify the changeset. The `Backpex.Fields.HasMany` uses this callback to put the linked associations into the changeset. """ @callback before_changeset( - changeset :: Phoenix.LiveView.Socket.t(), + changeset :: Socket.t(), attrs :: map(), metadata :: keyword(), repo :: module(), diff --git a/lib/backpex/fields/belongs_to.ex b/lib/backpex/fields/belongs_to.ex index 8165341bf..29708783b 100644 --- a/lib/backpex/fields/belongs_to.ex +++ b/lib/backpex/fields/belongs_to.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.BelongsTo do @config_schema [ display_field: [ diff --git a/lib/backpex/fields/boolean.ex b/lib/backpex/fields/boolean.ex index 9345db88d..e541c35e0 100644 --- a/lib/backpex/fields/boolean.ex +++ b/lib/backpex/fields/boolean.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.Boolean do @config_schema [ debounce: [ diff --git a/lib/backpex/fields/currency.ex b/lib/backpex/fields/currency.ex index 2e4801a0b..fc41b348b 100644 --- a/lib/backpex/fields/currency.ex +++ b/lib/backpex/fields/currency.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.Currency do @config_schema [ debounce: [ diff --git a/lib/backpex/fields/date.ex b/lib/backpex/fields/date.ex index 671df88a5..cd4d65dc4 100644 --- a/lib/backpex/fields/date.ex +++ b/lib/backpex/fields/date.ex @@ -1,4 +1,5 @@ # credo:disable-for-this-file Credo.Check.Design.DuplicatedCode +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.Date do @config_schema [ format: [ diff --git a/lib/backpex/fields/date_time.ex b/lib/backpex/fields/date_time.ex index 31c12d5bc..747b314cb 100644 --- a/lib/backpex/fields/date_time.ex +++ b/lib/backpex/fields/date_time.ex @@ -1,4 +1,5 @@ # credo:disable-for-this-file Credo.Check.Design.DuplicatedCode +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.DateTime do @config_schema [ format: [ diff --git a/lib/backpex/fields/email.ex b/lib/backpex/fields/email.ex index adcf273cd..8482815a8 100644 --- a/lib/backpex/fields/email.ex +++ b/lib/backpex/fields/email.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.Email do @config_schema [ placeholder: [ diff --git a/lib/backpex/fields/has_many.ex b/lib/backpex/fields/has_many.ex index bcd6f3223..e22e8c4da 100644 --- a/lib/backpex/fields/has_many.ex +++ b/lib/backpex/fields/has_many.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.HasMany do @config_schema [ display_field: [ diff --git a/lib/backpex/fields/has_many_through.ex b/lib/backpex/fields/has_many_through.ex index b13583dcb..1a0e7d446 100644 --- a/lib/backpex/fields/has_many_through.ex +++ b/lib/backpex/fields/has_many_through.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.HasManyThrough do @config_schema [ display_field: [ diff --git a/lib/backpex/fields/inline_crud.ex b/lib/backpex/fields/inline_crud.ex index b6d8051d9..9f9918df5 100644 --- a/lib/backpex/fields/inline_crud.ex +++ b/lib/backpex/fields/inline_crud.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.InlineCRUD do @config_schema [ type: [ diff --git a/lib/backpex/fields/multi_select.ex b/lib/backpex/fields/multi_select.ex index 0ac1f1c80..c08050971 100644 --- a/lib/backpex/fields/multi_select.ex +++ b/lib/backpex/fields/multi_select.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.MultiSelect do @config_schema [ options: [ diff --git a/lib/backpex/fields/number.ex b/lib/backpex/fields/number.ex index 7f4117876..4b766bb0f 100644 --- a/lib/backpex/fields/number.ex +++ b/lib/backpex/fields/number.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.Number do @config_schema [ placeholder: [ diff --git a/lib/backpex/fields/select.ex b/lib/backpex/fields/select.ex index 1df15afe4..b48ae19f4 100644 --- a/lib/backpex/fields/select.ex +++ b/lib/backpex/fields/select.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.Select do @config_schema [ options: [ diff --git a/lib/backpex/fields/text.ex b/lib/backpex/fields/text.ex index 0612d206e..77fb17dfa 100644 --- a/lib/backpex/fields/text.ex +++ b/lib/backpex/fields/text.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.Text do @config_schema [ placeholder: [ diff --git a/lib/backpex/fields/textarea.ex b/lib/backpex/fields/textarea.ex index da9c56793..30d7b6fe2 100644 --- a/lib/backpex/fields/textarea.ex +++ b/lib/backpex/fields/textarea.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.Textarea do @config_schema [ placeholder: [ diff --git a/lib/backpex/fields/time.ex b/lib/backpex/fields/time.ex index 7c01e9438..f22b3d04c 100644 --- a/lib/backpex/fields/time.ex +++ b/lib/backpex/fields/time.ex @@ -1,4 +1,5 @@ # credo:disable-for-this-file Credo.Check.Design.DuplicatedCode +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.Time do @config_schema [ format: [ diff --git a/lib/backpex/fields/upload.ex b/lib/backpex/fields/upload.ex index 3c03b2850..b299adc90 100644 --- a/lib/backpex/fields/upload.ex +++ b/lib/backpex/fields/upload.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.Upload do @config_schema [ upload_key: [ diff --git a/lib/backpex/fields/url.ex b/lib/backpex/fields/url.ex index 743664c55..2dd7547f6 100644 --- a/lib/backpex/fields/url.ex +++ b/lib/backpex/fields/url.ex @@ -1,3 +1,4 @@ +# quokka:skip-module-directive-reordering defmodule Backpex.Fields.URL do @config_schema [ placeholder: [ diff --git a/lib/backpex/filters/boolean.ex b/lib/backpex/filters/boolean.ex index 780ea541a..5aca3c24d 100644 --- a/lib/backpex/filters/boolean.ex +++ b/lib/backpex/filters/boolean.ex @@ -49,13 +49,13 @@ defmodule Backpex.Filters.Boolean do defmacro __using__(_opts) do quote do + @behaviour Backpex.Filters.Boolean + use BackpexWeb, :filter use Backpex.Filter alias Backpex.Filters.Boolean, as: BooleanFilter - @behaviour Backpex.Filters.Boolean - @impl Backpex.Filter def type(_assigns), do: {:array, :string} diff --git a/lib/backpex/filters/filter.ex b/lib/backpex/filters/filter.ex index 4fea336be..91a0710a5 100644 --- a/lib/backpex/filters/filter.ex +++ b/lib/backpex/filters/filter.ex @@ -38,10 +38,13 @@ defmodule Backpex.Filter do """ + alias Phoenix.LiveView.Rendered + alias Phoenix.LiveView.Socket + @doc """ Defines whether the filter can be used or not. """ - @callback can?(Phoenix.LiveView.Socket.assigns()) :: boolean() + @callback can?(Socket.assigns()) :: boolean() @doc """ If no label is defined on the filter map, this value is used as the filter label. @@ -120,12 +123,12 @@ defmodule Backpex.Filter do @doc """ Renders the filters selected value(s). """ - @callback render(Phoenix.LiveView.Socket.assigns()) :: Phoenix.LiveView.Rendered.t() + @callback render(Socket.assigns()) :: Rendered.t() @doc """ Renders the filters options form. """ - @callback render_form(Phoenix.LiveView.Socket.assigns()) :: Phoenix.LiveView.Rendered.t() + @callback render_form(Socket.assigns()) :: Rendered.t() @optional_callbacks label: 0 diff --git a/lib/backpex/filters/multi_select.ex b/lib/backpex/filters/multi_select.ex index b2a76a07e..5fe334535 100644 --- a/lib/backpex/filters/multi_select.ex +++ b/lib/backpex/filters/multi_select.ex @@ -37,13 +37,13 @@ defmodule Backpex.Filters.MultiSelect do defmacro __using__(_opts) do quote do + @behaviour Backpex.Filters.Select + use BackpexWeb, :filter use Backpex.Filter alias Backpex.Filters.MultiSelect, as: MultiSelectFilter - @behaviour Backpex.Filters.Select - @impl Backpex.Filter def type(_assigns), do: {:array, :string} diff --git a/lib/backpex/filters/range.ex b/lib/backpex/filters/range.ex index b93e861e5..d622ecd44 100644 --- a/lib/backpex/filters/range.ex +++ b/lib/backpex/filters/range.ex @@ -35,13 +35,13 @@ defmodule Backpex.Filters.Range do defmacro __using__(_opts) do quote do + @behaviour Backpex.Filters.Range + use BackpexWeb, :filter use Backpex.Filter alias Backpex.Filters.Range, as: RangeFilter - @behaviour RangeFilter - @impl Backpex.Filter def type(_assigns), do: :map diff --git a/lib/backpex/filters/select.ex b/lib/backpex/filters/select.ex index ebf712333..97acde385 100644 --- a/lib/backpex/filters/select.ex +++ b/lib/backpex/filters/select.ex @@ -44,13 +44,13 @@ defmodule Backpex.Filters.Select do defmacro __using__(_opts) do quote do + @behaviour Backpex.Filters.Select + use BackpexWeb, :filter use Backpex.Filter alias Backpex.Filters.Select, as: SelectFilter - @behaviour Backpex.Filters.Select - @impl Backpex.Filter def type(_assigns), do: :string diff --git a/lib/backpex/html/form.ex b/lib/backpex/html/form.ex index d1a1b592e..798553953 100644 --- a/lib/backpex/html/form.ex +++ b/lib/backpex/html/form.ex @@ -7,6 +7,7 @@ defmodule Backpex.HTML.Form do import Backpex.HTML.CoreComponents alias Phoenix.HTML.Form + alias Phoenix.HTML.FormField require Backpex @@ -26,7 +27,7 @@ defmodule Backpex.HTML.Form do values: ~w(checkbox color date datetime-local email file hidden month number password range radio search select tel text textarea time toggle url week) - attr :field, Phoenix.HTML.FormField, doc: "a form field struct retrieved from the form, for example: @form[:email]" + attr :field, FormField, doc: "a form field struct retrieved from the form, for example: @form[:email]" attr :errors, :list, default: [] attr :checked, :boolean, doc: "the checked flag for checkbox inputs" @@ -46,7 +47,7 @@ defmodule Backpex.HTML.Form do slot :inner_block - def input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do + def input(%{field: %FormField{} = field} = assigns) do assigns |> prepare_field_assigns(field, assigns.translate_error_fun) |> assign_new(:name, fn -> if assigns.multiple, do: field.name <> "[]", else: field.name end) @@ -181,7 +182,7 @@ defmodule Backpex.HTML.Form do attr :help_text, :string, default: nil attr :value, :any - attr :field, Phoenix.HTML.FormField, doc: "a form field struct retrieved from the form, for example: @form[:email]" + attr :field, FormField, doc: "a form field struct retrieved from the form, for example: @form[:email]" attr :errors, :list, default: [] @@ -206,7 +207,7 @@ defmodule Backpex.HTML.Form do attr :rest, :global, include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength multiple pattern placeholder readonly required rows size step) - def currency_input(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do + def currency_input(%{field: %FormField{} = field} = assigns) do assigns |> prepare_field_assigns(field, assigns.translate_error_fun) |> assign_new(:name, fn -> field.name end) diff --git a/lib/backpex/html/layout.ex b/lib/backpex/html/layout.ex index ae7a5e918..aea49d009 100644 --- a/lib/backpex/html/layout.ex +++ b/lib/backpex/html/layout.ex @@ -8,6 +8,7 @@ defmodule Backpex.HTML.Layout do import Backpex.HTML.CoreComponents alias Backpex.Router + alias Phoenix.HTML.FormField require Backpex @@ -635,7 +636,7 @@ defmodule Backpex.HTML.Layout do def input_label(assigns) do assigns = case assigns.for do - %Phoenix.HTML.FormField{} = field -> assign(assigns, :rest, Map.put(assigns.rest, :for, field.id)) + %FormField{} = field -> assign(assigns, :rest, Map.put(assigns.rest, :for, field.id)) id -> assign(assigns, :rest, Map.put(assigns.rest, :for, id)) end diff --git a/lib/backpex/html/resource.ex b/lib/backpex/html/resource.ex index 24311f438..6a1d9ee51 100644 --- a/lib/backpex/html/resource.ex +++ b/lib/backpex/html/resource.ex @@ -4,10 +4,10 @@ defmodule Backpex.HTML.Resource do """ use BackpexWeb, :html - import Phoenix.LiveView.TagEngine import Backpex.HTML.CoreComponents import Backpex.HTML.Form import Backpex.HTML.Layout + import Phoenix.LiveView.TagEngine alias Backpex.LiveResource alias Backpex.ResourceAction diff --git a/lib/backpex/init_assigns.ex b/lib/backpex/init_assigns.ex index 3d8383dbe..1a3430a74 100644 --- a/lib/backpex/init_assigns.ex +++ b/lib/backpex/init_assigns.ex @@ -4,6 +4,7 @@ defmodule Backpex.InitAssigns do """ use BackpexWeb, :html + import Phoenix.LiveView def on_mount(:default, _params, _session, socket) do diff --git a/lib/backpex/item_actions/delete.ex b/lib/backpex/item_actions/delete.ex index 8104b9d1e..e8f88421e 100644 --- a/lib/backpex/item_actions/delete.ex +++ b/lib/backpex/item_actions/delete.ex @@ -7,8 +7,8 @@ defmodule Backpex.ItemActions.Delete do alias Backpex.Resource - require Logger require Backpex + require Logger @impl Backpex.ItemAction def icon(assigns, _item) do diff --git a/lib/backpex/item_actions/item_action.ex b/lib/backpex/item_actions/item_action.ex index 06b6eedd9..1a58def9e 100644 --- a/lib/backpex/item_actions/item_action.ex +++ b/lib/backpex/item_actions/item_action.ex @@ -4,10 +4,16 @@ defmodule Backpex.ItemAction do """ import Phoenix.Component + alias Backpex.ItemActions.Delete + alias Backpex.ItemActions.Edit + alias Backpex.ItemActions.Show + alias Phoenix.LiveView.Rendered + alias Phoenix.LiveView.Socket + @doc """ Action icon """ - @callback icon(assigns :: map(), item :: struct()) :: %Phoenix.LiveView.Rendered{} + @callback icon(assigns :: map(), item :: struct()) :: %Rendered{} @doc """ A list of fields to be displayed in the item action. See `Backpex.Field`. In addition you have to provide @@ -97,8 +103,8 @@ defmodule Backpex.ItemAction do You are only allowed to return `{:error, changeset}` if the action has a form. Otherwise Backpex will throw an ArgumentError. """ - @callback handle(socket :: Phoenix.LiveView.Socket.t(), items :: list(map()), params :: map() | struct()) :: - {:ok, Phoenix.LiveView.Socket.t()} | {:error, Ecto.Changeset.t()} + @callback handle(socket :: Socket.t(), items :: list(map()), params :: map() | struct()) :: + {:ok, Socket.t()} | {:error, Ecto.Changeset.t()} @optional_callbacks confirm: 1, confirm_label: 1, cancel_label: 1, changeset: 3, fields: 0, link: 2, handle: 3 @@ -107,10 +113,11 @@ defmodule Backpex.ItemAction do """ defmacro __using__(_opts) do quote do - @before_compile Backpex.ItemAction @behaviour Backpex.ItemAction require Backpex + + @before_compile Backpex.ItemAction end end @@ -241,15 +248,15 @@ defmodule Backpex.ItemAction do def default_actions do [ show: %{ - module: Backpex.ItemActions.Show, + module: Show, only: [:row] }, edit: %{ - module: Backpex.ItemActions.Edit, + module: Edit, only: [:row, :show] }, delete: %{ - module: Backpex.ItemActions.Delete, + module: Delete, only: [:row, :index, :show] } ] diff --git a/lib/backpex/live_components/form_component.ex b/lib/backpex/live_components/form_component.ex index cbf54059e..9ca5410b7 100644 --- a/lib/backpex/live_components/form_component.ex +++ b/lib/backpex/live_components/form_component.ex @@ -4,9 +4,13 @@ defmodule Backpex.FormComponent do """ use BackpexWeb, :html use Phoenix.LiveComponent - alias Backpex.Fields.Upload + + alias Backpex.Field + alias Backpex.ItemAction + alias Backpex.LiveResource alias Backpex.Resource alias Backpex.ResourceAction + alias Phoenix.Component require Backpex @@ -71,7 +75,7 @@ defmodule Backpex.FormComponent do defp assign_form(socket) do changeset = socket.assigns.changeset - form = Phoenix.Component.to_form(changeset, as: :change) + form = Component.to_form(changeset, as: :change) assign(socket, :form, form) end @@ -97,7 +101,7 @@ defmodule Backpex.FormComponent do |> changeset_function.(change, metadata) |> Map.put(:action, :validate) - form = Phoenix.Component.to_form(changeset, as: :change) + form = Component.to_form(changeset, as: :change) send(self(), {:update_changeset, changeset}) @@ -121,7 +125,7 @@ defmodule Backpex.FormComponent do opts = [target: target, assocs: assocs] changeset = Resource.change(item, change, fields, socket.assigns, live_resource, opts) - form = Phoenix.Component.to_form(changeset, as: :change) + form = Component.to_form(changeset, as: :change) send(self(), {:update_changeset, changeset}) @@ -158,7 +162,13 @@ defmodule Backpex.FormComponent do |> Map.get(:removed_uploads, []) |> Keyword.update(upload_key, [file_key], fn existing -> [file_key | existing] end) - files = Upload.existing_file_paths(field, socket.assigns.item, Keyword.get(removed_uploads, upload_key, [])) + files = + Backpex.Fields.Upload.existing_file_paths( + field, + socket.assigns.item, + Keyword.get(removed_uploads, upload_key, []) + ) + uploaded_files = Keyword.put(socket.assigns[:uploaded_files], upload_key, files) socket @@ -236,7 +246,7 @@ defmodule Backpex.FormComponent do |> noreply() {:error, changeset} when is_struct(changeset) -> - form = Phoenix.Component.to_form(changeset, as: :change) + form = Component.to_form(changeset, as: :change) send(self(), {:update_changeset, changeset}) @@ -283,7 +293,7 @@ defmodule Backpex.FormComponent do |> noreply() {:error, changeset} when is_struct(changeset) -> - form = Phoenix.Component.to_form(changeset, as: :change) + form = Component.to_form(changeset, as: :change) send(self(), {:update_changeset, changeset}) @@ -324,7 +334,7 @@ defmodule Backpex.FormComponent do |> noreply() else {:error, changeset} -> - form = Phoenix.Component.to_form(changeset, as: :change) + form = Component.to_form(changeset, as: :change) send(self(), {:update_changeset, changeset}) @@ -360,7 +370,7 @@ defmodule Backpex.FormComponent do params = drop_readonly_changes(params, fields, assigns) result = - if Backpex.ItemAction.has_form?(action_to_confirm) do + if ItemAction.has_form?(action_to_confirm) do changeset_function = fn item, changes, metadata -> action_to_confirm.module.changeset(item, changes, metadata) end @@ -386,7 +396,7 @@ defmodule Backpex.FormComponent do |> noreply() else {:error, changeset} -> - form = Phoenix.Component.to_form(changeset, as: :change) + form = Component.to_form(changeset, as: :change) socket |> assign(:show_form_errors, true) @@ -406,7 +416,7 @@ defmodule Backpex.FormComponent do end defp drop_readonly_changes(change, fields, assigns) do - Backpex.Field.drop_readonly_changes(change, fields, assigns) + Field.drop_readonly_changes(change, fields, assigns) end defp drop_unused_changes(change) do @@ -417,7 +427,7 @@ defmodule Backpex.FormComponent do end defp return_to_path("continue", live_resource, _socket, %{current_url: url}, :new, item) do - primary_value = Backpex.LiveResource.primary_value(item, live_resource) + primary_value = LiveResource.primary_value(item, live_resource) url |> URI.parse() diff --git a/lib/backpex/live_resource.ex b/lib/backpex/live_resource.ex index 35311ce66..21ac4a346 100644 --- a/lib/backpex/live_resource.ex +++ b/lib/backpex/live_resource.ex @@ -11,6 +11,8 @@ defmodule Backpex.LiveResource do alias Backpex.Resource alias Backpex.Router + alias Phoenix.LiveView.Rendered + alias Phoenix.LiveView.Socket @options_schema [ adapter: [ @@ -172,7 +174,7 @@ defmodule Backpex.LiveResource do - `:metrics` """ @callback render_resource_slot(assigns :: map(), action :: atom(), position :: atom()) :: - %Phoenix.LiveView.Rendered{} + %Rendered{} @doc """ A optional keyword list of [filters](Backpex.Filter.html) to be used on the index view. @@ -193,7 +195,7 @@ defmodule Backpex.LiveResource do Must return either a `{module, function_name}` tuple or a function with arity 1. """ - @callback layout(assigns :: map()) :: {module(), atom()} | (map() -> Phoenix.LiveView.Rendered.t()) + @callback layout(assigns :: map()) :: {module(), atom()} | (map() -> Rendered.t()) @doc """ A list of metrics shown on the index view of your resource. @@ -203,26 +205,26 @@ defmodule Backpex.LiveResource do @doc """ This function is executed when an item has been created. """ - @callback on_item_created(socket :: Phoenix.LiveView.Socket.t(), item :: map()) :: - Phoenix.LiveView.Socket.t() + @callback on_item_created(socket :: Socket.t(), item :: map()) :: + Socket.t() @doc """ This function is executed when an item has been updated. """ - @callback on_item_updated(socket :: Phoenix.LiveView.Socket.t(), item :: map()) :: - Phoenix.LiveView.Socket.t() + @callback on_item_updated(socket :: Socket.t(), item :: map()) :: + Socket.t() @doc """ This function is executed when an item has been deleted. """ - @callback on_item_deleted(socket :: Phoenix.LiveView.Socket.t(), item :: map()) :: - Phoenix.LiveView.Socket.t() + @callback on_item_deleted(socket :: Socket.t(), item :: map()) :: + Socket.t() @doc """ This function navigates to the specified path when an item has been created or updated. Defaults to the previous resource path (index or show). """ @callback return_to( - socket :: Phoenix.LiveView.Socket.t(), + socket :: Socket.t(), assigns :: map(), live_action :: atom(), form_action :: atom(), @@ -263,14 +265,10 @@ defmodule Backpex.LiveResource do """ defmacro __using__(opts) do quote bind_quoted: [opts: opts, options_schema: @options_schema] do - @before_compile Backpex.LiveResource @behaviour Backpex.LiveResource - @resource_opts NimbleOptions.validate!(opts, options_schema) - - @adapter_opts @resource_opts[:adapter].validate_config!(@resource_opts[:adapter_config]) - use BackpexWeb, :html + import Backpex.LiveResource import Phoenix.LiveView.Helpers @@ -278,6 +276,11 @@ defmodule Backpex.LiveResource do require Backpex + @before_compile Backpex.LiveResource + @resource_opts NimbleOptions.validate!(opts, options_schema) + + @adapter_opts @resource_opts[:adapter].validate_config!(@resource_opts[:adapter_config]) + def config(key), do: Keyword.get(@resource_opts, key) def adapter_config(key), do: Keyword.get(@adapter_opts, key) @@ -334,10 +337,10 @@ defmodule Backpex.LiveResource do for action <- ~w(Index Form Show)a do # credo:disable-for-next-line Credo.Check.Warning.UnsafeToAtom defmodule String.to_atom("#{__MODULE__}.#{action}") do - @resource_opts NimbleOptions.validate!(opts, options_schema) - use Phoenix.LiveView + @resource_opts NimbleOptions.validate!(opts, options_schema) + @action_module String.to_existing_atom("Elixir.Backpex.LiveResource.#{action}") insert_on_mount_hooks(@resource_opts[:on_mount]) diff --git a/lib/backpex/live_resource/index.ex b/lib/backpex/live_resource/index.ex index 92df3331d..3cb79f7d7 100644 --- a/lib/backpex/live_resource/index.ex +++ b/lib/backpex/live_resource/index.ex @@ -10,7 +10,6 @@ defmodule Backpex.LiveResource.Index do alias Backpex.PaginationValidation alias Backpex.Resource alias Backpex.Router - alias Phoenix.LiveView require Backpex diff --git a/lib/backpex/metric.ex b/lib/backpex/metric.ex index 755c05a33..5218952ef 100644 --- a/lib/backpex/metric.ex +++ b/lib/backpex/metric.ex @@ -7,10 +7,12 @@ defmodule Backpex.Metric do implementing this behaviour. """ + alias Phoenix.LiveView.Rendered + @doc """ Used to render the metric as a heex template on the index views. """ - @callback render(assigns :: map()) :: %Phoenix.LiveView.Rendered{} + @callback render(assigns :: map()) :: %Rendered{} @callback query(query :: Ecto.Queryable.t(), select :: any(), repo :: Ecto.Repo.t()) :: Ecto.Schema.t() | term() | nil @callback format(data :: any(), format :: any()) :: term() diff --git a/lib/backpex/resource_action.ex b/lib/backpex/resource_action.ex index 3cfc108f2..35625a6bc 100644 --- a/lib/backpex/resource_action.ex +++ b/lib/backpex/resource_action.ex @@ -8,6 +8,8 @@ defmodule Backpex.ResourceAction do > In addition it will implement the `c:base_schema/1` function in order to generate a schemaless changeset by default. ''' + alias Phoenix.LiveView.Socket + @doc """ The title of the resource action. It will be part of the page header and slide over title. """ @@ -64,8 +66,8 @@ defmodule Backpex.ResourceAction do You have to use `Phoenix.LiveView.put_flash/3` along with the socket to show a success or error message. """ - @callback handle(socket :: Phoenix.LiveView.Socket.t(), data :: map()) :: - {:ok, Phoenix.LiveView.Socket.t()} | {:error, Ecto.Changeset.t()} + @callback handle(socket :: Socket.t(), data :: map()) :: + {:ok, Socket.t()} | {:error, Ecto.Changeset.t()} @doc """ Defines `Backpex.ResourceAction` behaviour. diff --git a/lib/backpex_web.ex b/lib/backpex_web.ex index 81f517db2..08ba130d6 100644 --- a/lib/backpex_web.ex +++ b/lib/backpex_web.ex @@ -14,6 +14,7 @@ defmodule BackpexWeb do def html do quote do use Phoenix.Component + unquote(html_helpers()) end end @@ -24,11 +25,13 @@ defmodule BackpexWeb do def field do quote do use Phoenix.LiveComponent + alias Backpex.HTML alias Backpex.HTML.Form, as: BackpexForm alias Backpex.HTML.Layout alias Backpex.LiveResource alias Phoenix.HTML.Form, as: PhoenixForm + unquote(html_helpers()) end end @@ -40,8 +43,11 @@ defmodule BackpexWeb do quote do use Phoenix.Component use Backpex.ItemAction + import Phoenix.LiveView + alias Backpex.Router + unquote(html_helpers()) end end @@ -49,23 +55,28 @@ defmodule BackpexWeb do def filter do quote do use Phoenix.Component - import Ecto.Query, warn: false + import Backpex.HTML.Form, only: [error: 1] + import Ecto.Query, warn: false + unquote(html_helpers()) end end def metric do quote do + @behaviour Backpex.Metric + use Phoenix.Component + import Ecto.Query - @behaviour Backpex.Metric end end defp html_helpers do quote do import Phoenix.HTML + alias Phoenix.LiveView.JS @doc false diff --git a/lib/mix/tasks/backpex.install.ex b/lib/mix/tasks/backpex.install.ex index 405baa862..620329f00 100644 --- a/lib/mix/tasks/backpex.install.ex +++ b/lib/mix/tasks/backpex.install.ex @@ -53,9 +53,9 @@ if Code.ensure_loaded?(Igniter) and Code.ensure_loaded?(IgniterJs) do use Igniter.Mix.Task alias Backpex.Mix.IgniterHelpers - alias Igniter.Code.Common alias Igniter.Libs.Phoenix + alias Igniter.Mix.Task.Info alias Igniter.Project.Config alias Igniter.Project.Formatter alias Igniter.Project.Module @@ -70,7 +70,7 @@ if Code.ensure_loaded?(Igniter) and Code.ensure_loaded?(IgniterJs) do @impl Igniter.Mix.Task def info(_argv, _composing_task) do - %Igniter.Mix.Task.Info{ + %Info{ adds_deps: [igniter_js: "~> 0.4"], example: __MODULE__.Docs.example(), schema: [app_js_path: :string, app_css_path: :string, no_layout: :boolean], diff --git a/test/controllers/cookie_controller_test.exs b/test/controllers/cookie_controller_test.exs index 0b7be5952..05d7ec2ee 100644 --- a/test/controllers/cookie_controller_test.exs +++ b/test/controllers/cookie_controller_test.exs @@ -1,8 +1,8 @@ defmodule Backpex.Controllers.CookieControllerTest do use ExUnit.Case, async: true - import Plug.Conn import Phoenix.ConnTest + import Plug.Conn alias Backpex.CookieController diff --git a/test/doc_test.exs b/test/doc_test.exs index 6dfa18892..8c76c4beb 100644 --- a/test/doc_test.exs +++ b/test/doc_test.exs @@ -1,3 +1,4 @@ +# quokka:skip-module-directives defmodule DocTest do use ExUnit.Case, async: true diff --git a/test/router_test.exs b/test/router_test.exs index 31b701980..d0da9a159 100644 --- a/test/router_test.exs +++ b/test/router_test.exs @@ -23,8 +23,8 @@ defmodule Backpex.RouterTest do defmodule TestRouter do use Phoenix.Router, helpers: false - import Phoenix.LiveView.Router import Backpex.Router + import Phoenix.LiveView.Router # Basic route with defaults live_resources "/users", UserLive @@ -99,8 +99,8 @@ defmodule Backpex.RouterTest do defmodule InvalidRouter1 do use Phoenix.Router, helpers: false - import Phoenix.LiveView.Router import Backpex.Router + import Phoenix.LiveView.Router # Pass a string to only, which should be a list of atoms live_resources "/bad", BadLive, only: "index" @@ -113,8 +113,8 @@ defmodule Backpex.RouterTest do defmodule InvalidRouter2 do use Phoenix.Router, helpers: false - import Phoenix.LiveView.Router import Backpex.Router + import Phoenix.LiveView.Router # Pass an unknown option live_resources "/bad", BadLive, unknown_option: true @@ -126,8 +126,8 @@ defmodule Backpex.RouterTest do defmodule ValidContainerRouter do use Phoenix.Router, helpers: false - import Phoenix.LiveView.Router import Backpex.Router + import Phoenix.LiveView.Router live_resources "/valid", ValidLive, container: {:div, class: "valid"} end @@ -138,8 +138,8 @@ defmodule Backpex.RouterTest do defmodule InvalidRouter3 do use Phoenix.Router, helpers: false - import Phoenix.LiveView.Router import Backpex.Router + import Phoenix.LiveView.Router live_resources "/bad", BadLive, metadata: "not a map" end @@ -149,8 +149,8 @@ defmodule Backpex.RouterTest do defmodule InvalidRouter4 do use Phoenix.Router, helpers: false - import Phoenix.LiveView.Router import Backpex.Router + import Phoenix.LiveView.Router live_resources "/bad", BadLive, private: [:not, :a, :map] end