diff --git a/CHANGELOG.md b/CHANGELOG.md index dc94fc4117e..295a3813403 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ #### Minor +* "Create another" checkbox for the new resource page. [#4477][] by [@bolshakov][] * Page supports belongs_to [#4759][] by [@Fivell][] and [@zorab47][] * Support for custom sorting strategies [#4768][] by [@Fivell][] * Stream CSV downloads as they're generated [#3038][] by [@craigmcnamara][] @@ -109,24 +110,29 @@ Please check [0-6-stable](https://github.com/activeadmin/activeadmin/blob/0-6-st [#3731]: https://github.com/activeadmin/activeadmin/issues/3731 [#3783]: https://github.com/activeadmin/activeadmin/issues/3783 [#4187]: https://github.com/activeadmin/activeadmin/issues/4187 +[#4477]: https://github.com/activeadmin/activeadmin/pull/4477 [#4759]: https://github.com/activeadmin/activeadmin/pull/4759 [#4768]: https://github.com/activeadmin/activeadmin/pull/4768 [#4848]: https://github.com/activeadmin/activeadmin/pull/4848 [#4867]: https://github.com/activeadmin/activeadmin/pull/4867 -[@PChambino]: https://github.com/PChambino -[@TimPetricola]: https://github.com/TimPetricola + +[@bolshakov]: https://github.com/bolshakov [@chancancode]: https://github.com/chancancode [@craigmcnamara]: https://github.com/craigmcnamara -[@drn]: https://github.com/drn +[@deivid-rodriguez]: https://github.com/deivid-rodriguez [@dmitry]: https://github.com/dmitry +[@drn]: https://github.com/drn +[@Fivell]: https://github.com/Fivell [@gonzedge]: https://github.com/gonzedge [@johnnyshields]: https://github.com/johnnyshields +[@PChambino]: https://github.com/PChambino +[@PChambino]: https://github.com/PChambino [@potatosalad]: https://github.com/potatosalad [@pranas]: https://github.com/pranas [@seanlinsley]: https://github.com/seanlinsley [@shekibobo]: https://github.com/shekibobo [@timoschilling]: https://github.com/timoschilling +[@TimPetricola]: https://github.com/TimPetricola +[@TimPetricola]: https://github.com/TimPetricola [@varyonic]: https://github.com/varyonic [@zorab47]: https://github.com/zorab47 -[@Fivell]: https://github.com/Fivell -[@deivid-rodriguez]: https://github.com/deivid-rodriguez diff --git a/activeadmin.gemspec b/activeadmin.gemspec index 3e8a04589fc..4b72f1fe6cf 100644 --- a/activeadmin.gemspec +++ b/activeadmin.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new do |s| s.required_ruby_version = '>= 2.1' - s.add_dependency 'arbre', '~> 1.0', '>= 1.0.2' + s.add_dependency 'arbre', '>= 1.1.1' s.add_dependency 'bourbon' s.add_dependency 'coffee-rails' s.add_dependency 'formtastic', '~> 3.1' diff --git a/app/assets/stylesheets/active_admin/_forms.scss b/app/assets/stylesheets/active_admin/_forms.scss index ab93bbab99d..08e0fbd12ac 100644 --- a/app/assets/stylesheets/active_admin/_forms.scss +++ b/app/assets/stylesheets/active_admin/_forms.scss @@ -242,6 +242,16 @@ form { input[type=submit], input[type=button], button { margin-right: 10px; } } + .buttons .actions .create_another { + float: none; + margin-bottom: 10px; + + label { + float: none; + display: inline; + } + } + fieldset.buttons li, fieldset.actions li { float:left; padding: 0; diff --git a/config/locales/en.yml b/config/locales/en.yml index e73d0f58552..6923f1c3255 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -8,6 +8,7 @@ en: edit: "Edit" delete: "Delete" delete_confirmation: "Are you sure you want to delete this?" + create_another: "Create another %{model}" new_model: "New %{model}" edit_model: "Edit %{model}" delete_model: "Delete %{model}" diff --git a/docs/5-forms.md b/docs/5-forms.md index 4309cd75994..de563467d72 100644 --- a/docs/5-forms.md +++ b/docs/5-forms.md @@ -173,3 +173,22 @@ You can arrange content in tabs as shown below: f.actions end ``` + +## Customize the Create Another checkbox + +In order to simplify creating multiple resources you may enable ActiveAdmin to show nice "Create Another" checkbox alongside of Create Model +button. It may be enabled for the whole application: + +```ruby +ActiveAdmin.setup do |config| + config.create_another = true +end +``` + +or for the particular resource: + +```ruby +ActiveAdmin.register Post do + config.create_another = true +end +``` diff --git a/features/create_another.feature b/features/create_another.feature new file mode 100644 index 00000000000..1bf8aa4a52f --- /dev/null +++ b/features/create_another.feature @@ -0,0 +1,55 @@ +Feature: Create Another checkbox + + Background: + Given I am logged in + + Scenario: On a new page + Given a configuration of: + """ + ActiveAdmin.register Post do + config.create_another = true + + permit_params :custom_category_id, :author_id, :title, + :body, :position, :published_date, :starred + end + """ + Then I am on the index page for posts + And I follow "New Post" + When I fill in "Title" with "Hello World" + And I fill in "Body" with "This is the body" + And the "Create another Post" checkbox should not be checked + And I check "Create another" + And I press "Create Post" + Then I should see "Post was successfully created." + And I should see "New Post" + And the "Create another" checkbox should be checked + When I fill in "Title" with "Another Hello World" + And I fill in "Body" with "This is the another body" + And I uncheck "Create another" + And I press "Create Post" + Then I should see "Post was successfully created." + And I should see the attribute "Title" with "Another Hello World" + And I should see the attribute "Body" with "This is the another body" + + Scenario: Application config of false and a resource config of true + Given a configuration of: + """ + ActiveAdmin.application.create_another = false + ActiveAdmin.register Post do + config.create_another = true + end + """ + When I am on the new post page + Then I should see the element ".create_another" + Then the "Create another Post" checkbox should not be checked + + Scenario: Application config of true and a resource config of false + Given a configuration of: + """ + ActiveAdmin.application.create_another = true + ActiveAdmin.register Post do + config.create_another = false + end + """ + When I am on the new post page + Then I should not see the element ".create_another" diff --git a/features/edit_page.feature b/features/edit_page.feature index 55f82f684d3..9834f00a28c 100644 --- a/features/edit_page.feature +++ b/features/edit_page.feature @@ -23,6 +23,7 @@ Feature: Edit Page And the "Category" field should contain "" And the "Author" field should contain the option "John Doe" When I fill in "Title" with "Hello World from update" + And I should not see the element "Create another" When I press "Update Post" Then I should see "Post was successfully updated." And I should see the attribute "Title" with "Hello World from update" diff --git a/features/step_definitions/web_steps.rb b/features/step_definitions/web_steps.rb index 0626344f2bb..79108ff89f0 100644 --- a/features/step_definitions/web_steps.rb +++ b/features/step_definitions/web_steps.rb @@ -72,7 +72,12 @@ def with_scope(locator) Then /^the "([^"]*)" checkbox(?: within (.*))? should( not)? be checked$/ do |label, parent, negate| with_scope(parent) do - expect(find_field(label)['checked']).to negate ? eq(false) : eq(true) + checkbox = find_field(label) + if negate + expect(checkbox).not_to be_checked + else + expect(checkbox).to be_checked + end end end diff --git a/lib/active_admin/application.rb b/lib/active_admin/application.rb index d55ee70f16a..699291fdec3 100644 --- a/lib/active_admin/application.rb +++ b/lib/active_admin/application.rb @@ -89,6 +89,10 @@ def initialize # Display breadcrumbs inheritable_setting :breadcrumb, true + # Display create another checkbox on a new page + # @return [Boolean] (true) + inheritable_setting :create_another, false + # Default CSV options inheritable_setting :csv_options, { col_sep: ',', byte_order_mark: "\xEF\xBB\xBF" } diff --git a/lib/active_admin/resource.rb b/lib/active_admin/resource.rb index aadcc083fd3..1cce67af28e 100644 --- a/lib/active_admin/resource.rb +++ b/lib/active_admin/resource.rb @@ -54,6 +54,9 @@ def sort_order #Set order clause attr_writer :order_clause + # Display create another checkbox on a new page + # @return [Boolean] + attr_writer :create_another # Store a reference to the DSL so that we can dereference it during garbage collection. attr_accessor :dsl @@ -160,6 +163,10 @@ def order_clause @order_clause || namespace.order_clause end + def create_another + instance_variable_defined?(:@create_another) ? @create_another : namespace.create_another + end + def find_resource(id) resource = resource_class.public_send *method_for_find(id) (decorator_class && resource) ? decorator_class.new(resource) : resource diff --git a/lib/active_admin/resource_controller/data_access.rb b/lib/active_admin/resource_controller/data_access.rb index eb35b3197e2..85f5a7946e7 100644 --- a/lib/active_admin/resource_controller/data_access.rb +++ b/lib/active_admin/resource_controller/data_access.rb @@ -298,6 +298,23 @@ def assign_attributes(resource, attributes) def apply_decorations(resource) apply_decorator(resource) end + + # @return [String] + def smart_resource_url + if create_another? + new_resource_url(create_another: params[:create_another]) + else + super + end + end + + private + + # @return [Boolean] true if user requested to create one more + # resource after creating this one. + def create_another? + params[:create_another].present? + end end end end diff --git a/lib/active_admin/resource_dsl.rb b/lib/active_admin/resource_dsl.rb index 17ca69c4fae..39eecf94cd7 100644 --- a/lib/active_admin/resource_dsl.rb +++ b/lib/active_admin/resource_dsl.rb @@ -63,11 +63,16 @@ def includes(*args) def permit_params(*args, &block) param_key = config.param_key.to_sym belongs_to_param = config.belongs_to_param + create_another_param = :create_another if config.create_another controller do define_method :permitted_params do - params.permit *(active_admin_namespace.permitted_params + Array.wrap(belongs_to_param)), - param_key => block ? instance_exec(&block) : args + permitted_params = + active_admin_namespace.permitted_params + + Array.wrap(belongs_to_param) + + Array.wrap(create_another_param) + + params.permit(*permitted_params, param_key => block ? instance_exec(&block) : args) end end end diff --git a/lib/active_admin/views/components/active_admin_form.rb b/lib/active_admin/views/components/active_admin_form.rb index 4492e60fe9b..b8d805c22cb 100644 --- a/lib/active_admin/views/components/active_admin_form.rb +++ b/lib/active_admin/views/components/active_admin_form.rb @@ -72,10 +72,17 @@ def actions(*args, &block) end def commit_action_with_cancel_link + add_create_another_checkbox action(:submit) cancel_link end + def add_create_another_checkbox + if %w(new create).include?(action_name) && active_admin_config && active_admin_config.create_another + current_arbre_element.add_child(create_another_checkbox) + end + end + def has_many(*args, &block) insert_tag(HasManyProxy, form_builder, *args, &block) end @@ -91,6 +98,25 @@ def object def form_buffers raise "'form_buffers' has been removed from ActiveAdmin::FormBuilder, please read https://github.com/activeadmin/activeadmin/blob/master/docs/5-forms.md for details." end + + private + + def create_another_checkbox + create_another = params[:create_another] + label = @resource.class.model_name.human + Arbre::Context.new do + li do + input( + checked: create_another, + id: 'create_another', + class: 'create_another', + name: 'create_another', + type: 'checkbox', + ) + label(I18n.t('active_admin.create_another', model: label), for: 'create_another') + end + end + end end class SemanticInputsProxy < FormtasticProxy diff --git a/lib/generators/active_admin/install/templates/active_admin.rb.erb b/lib/generators/active_admin/install/templates/active_admin.rb.erb index a699d1d6aad..b61ca1592e6 100644 --- a/lib/generators/active_admin/install/templates/active_admin.rb.erb +++ b/lib/generators/active_admin/install/templates/active_admin.rb.erb @@ -179,6 +179,13 @@ ActiveAdmin.setup do |config| # # config.breadcrumb = false + # == Create Another Checkbox + # + # Create another checkbox is disabled by default. You can customize it for individual + # resources or you can enable them globally from here. + # + # config.create_another = true + # == Register Stylesheets & Javascripts # # We recommend using the built in Active Admin layout and loading diff --git a/spec/unit/form_builder_spec.rb b/spec/unit/form_builder_spec.rb index 7c43ee3da53..b15bd1d8621 100644 --- a/spec/unit/form_builder_spec.rb +++ b/spec/unit/form_builder_spec.rb @@ -30,6 +30,10 @@ def view.fa_icon(*args) args.inspect end + def view.action_name + 'edit' + end + view end @@ -157,13 +161,39 @@ def build_form(options = {}, form_object = Post.new, &block) end expect(body).to have_selector("[id=post_title]", count: 1) end - it "should generate one button and a cancel link" do + + context "create another checkbox" do + subject do + build_form do |f| + f.actions + end + end + + %w(new create).each do |action_name| + it "generates create another checkbox on #{action_name} page" do + expect(helpers).to receive(:action_name) { action_name } + allow(helpers).to receive(:active_admin_config) { instance_double(ActiveAdmin::Resource, create_another: true) } + + is_expected.to have_selector("[type=checkbox]", count: 1) + .and have_selector("[name=create_another]", count: 1) + end + end + + %w(show edit update).each do |action_name| + it "doesn't generate create another checkbox on #{action_name} page" do + is_expected.not_to have_selector("[name=create_another]", count: 1) + end + end + end + + it "should generate one button create another checkbox and a cancel link" do body = build_form do |f| f.actions end expect(body).to have_selector("[type=submit]", count: 1) expect(body).to have_selector("[class=cancel]", count: 1) end + it "should generate multiple actions" do body = build_form do |f| f.actions do