From 5bc06902ebe2c7c59bf338ed0dfeb00ba37ea0db Mon Sep 17 00:00:00 2001 From: T Floyd Wright Date: Fri, 15 May 2026 09:45:23 -0800 Subject: [PATCH] fix: only flag same-level create/update conflicts PR #144 raised whenever `create_with: false` appeared at any level while a custom `:create` component appeared at any other level, treating cross-level configurations as contradictory. That blocks the pattern #139 describes: disable create globally, then re-enable it per-resource via a custom component. Walk each level independently. A configuration is only contradictory when a single level sets both the disabling option and the custom component; cross-level overrides resolve normally with the more-specific level winning. --- lib/live_admin/router.ex | 22 ++++++++++---------- test/live_admin/router_test.exs | 37 +++++++++++++++++++++++++++------ 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/lib/live_admin/router.ex b/lib/live_admin/router.ex index f0a669e..03ef5b5 100644 --- a/lib/live_admin/router.ex +++ b/lib/live_admin/router.ex @@ -98,17 +98,17 @@ defmodule LiveAdmin.Router do resource_opts = resource_mod.__live_admin_config__() levels = [resource_opts, scope_opts, app_opts] - Enum.each(@disabled_with_custom_component, fn {with_key, component_key} -> - disabled? = Enum.any?(levels, &(Keyword.get(&1, with_key) == false)) - - component_set? = - Enum.any?(levels, &Keyword.has_key?(Keyword.get(&1, :components, []), component_key)) - - if disabled? and component_set? do - raise ArgumentError, - "invalid config for resource #{inspect(resource_mod)}: " <> - "#{with_key}: false cannot be combined with a custom :#{component_key} component" - end + Enum.each(levels, fn level -> + Enum.each(@disabled_with_custom_component, fn {with_key, component_key} -> + disabled? = Keyword.get(level, with_key) == false + component_set? = Keyword.has_key?(Keyword.get(level, :components, []), component_key) + + if disabled? and component_set? do + raise ArgumentError, + "invalid config for resource #{inspect(resource_mod)}: " <> + "#{with_key}: false cannot be combined with a custom :#{component_key} component at the same level" + end + end) end) end diff --git a/test/live_admin/router_test.exs b/test/live_admin/router_test.exs index 36c4051..ecb5045 100644 --- a/test/live_admin/router_test.exs +++ b/test/live_admin/router_test.exs @@ -3,7 +3,7 @@ defmodule LiveAdmin.RouterTest do alias LiveAdmin.Router - describe "create_with: false at resource level with custom :create component at resource level" do + describe "create_with: false and custom :create component at the resource level" do test "raises ArgumentError" do assert_raise ArgumentError, ~r/create_with: false.*:create component/, fn -> Router.__validate_config__!(LiveAdminTest.UserWithCustomCreate, [], []) @@ -11,26 +11,51 @@ defmodule LiveAdmin.RouterTest do end end - describe "create_with: false at scope level with custom :create component at resource level" do + describe "create_with: false and custom :create component at the scope level" do test "raises ArgumentError" do assert_raise ArgumentError, ~r/create_with: false.*:create component/, fn -> Router.__validate_config__!( - LiveAdminTest.UserWithCustomCreateOnly, - [create_with: false], + LiveAdminTest.User, + [create_with: false, components: [create: LiveAdminTest.CustomFormComponent]], [] ) end end end - describe "update_with: false at app level with custom :edit component at resource level" do + describe "update_with: false and custom :edit component at the app level" do test "raises ArgumentError" do assert_raise ArgumentError, ~r/update_with: false.*:edit component/, fn -> - Router.__validate_config__!(LiveAdminTest.UserWithCustomEditOnly, [], update_with: false) + Router.__validate_config__!( + LiveAdminTest.User, + [], + update_with: false, + components: [edit: LiveAdminTest.CustomFormComponent] + ) end end end + describe "create_with: false at scope level with custom :create component at resource level" do + test "returns :ok" do + assert :ok == + Router.__validate_config__!( + LiveAdminTest.UserWithCustomCreateOnly, + [create_with: false], + [] + ) + end + end + + describe "update_with: false at app level with custom :edit component at resource level" do + test "returns :ok" do + assert :ok == + Router.__validate_config__!(LiveAdminTest.UserWithCustomEditOnly, [], + update_with: false + ) + end + end + describe "resource without conflicting config" do test "returns :ok" do assert :ok == Router.__validate_config__!(LiveAdminTest.User, [], [])