diff --git a/app/components/avo/views/resource_index_component.rb b/app/components/avo/views/resource_index_component.rb index b34bcad74..92779c8c7 100644 --- a/app/components/avo/views/resource_index_component.rb +++ b/app/components/avo/views/resource_index_component.rb @@ -103,6 +103,7 @@ def attach_path paths: [*current_path, "new"], query: { view: @parent_resource&.view&.to_s, + turbo_frame: params[:turbo_frame], for_attribute: field&.try(:for_attribute) }.compact ) diff --git a/app/controllers/avo/associations_controller.rb b/app/controllers/avo/associations_controller.rb index fad9c6996..2cba58634 100644 --- a/app/controllers/avo/associations_controller.rb +++ b/app/controllers/avo/associations_controller.rb @@ -77,18 +77,10 @@ def new end def create - respond_to do |format| - if create_association - format.html { - redirect_back fallback_location: resource_view_response_path, - notice: t("avo.attachment_class_attached", attachment_class: @related_resource.name) - } - else - flash[:error] = t("avo.attachment_failed", attachment_class: @related_resource.name) - format.turbo_stream { - render turbo_stream: turbo_stream.append("alerts", partial: "avo/partials/all_alerts") - } - end + if create_association + create_success_action + else + create_fail_action end end @@ -118,9 +110,7 @@ def destroy @record.send(:"#{association_name}=", nil) end - respond_to do |format| - format.html { redirect_to params[:referrer] || resource_view_response_path, notice: t("avo.attachment_class_detached", attachment_class: @attachment_class) } - end + destroy_success_action end private @@ -238,5 +228,50 @@ def new_join_record fields: @attach_fields, ) end + + def create_success_action + flash[:notice] = t("avo.attachment_class_attached", attachment_class: @related_resource.name) + + respond_to do |format| + if params[:turbo_frame].present? + format.turbo_stream { render turbo_stream: reload_frame_turbo_streams } + else + format.html { redirect_back fallback_location: resource_view_response_path } + end + end + end + + def reload_frame_turbo_streams + turbo_streams = super + + # We want to close the modal if the user wants to add just one record + turbo_streams << turbo_stream.close_modal if params[:button] != "attach_another" + + turbo_streams + end + + def create_fail_action + flash[:error] = t("avo.attachment_failed", attachment_class: @related_resource.name) + + respond_to do |format| + format.turbo_stream { + render turbo_stream: turbo_stream.append("alerts", partial: "avo/partials/all_alerts") + } + end + end + + def destroy_success_action + flash[:notice] = t("avo.attachment_class_detached", attachment_class: @attachment_class) + + respond_to do |format| + if params[:turbo_frame].present? + format.turbo_stream do + render turbo_stream: reload_frame_turbo_streams + end + else + format.html { redirect_to params[:referrer] || resource_view_response_path } + end + end + end end end diff --git a/app/controllers/avo/base_controller.rb b/app/controllers/avo/base_controller.rb index 90dc73f91..50ad7e31b 100644 --- a/app/controllers/avo/base_controller.rb +++ b/app/controllers/avo/base_controller.rb @@ -537,8 +537,16 @@ def resource_view_response_path end def destroy_success_action + flash[:notice] = destroy_success_message + respond_to do |format| - format.html { redirect_to after_destroy_path, notice: destroy_success_message } + if params[:turbo_frame] + format.turbo_stream do + render turbo_stream: reload_frame_turbo_streams + end + else + format.html { redirect_to after_destroy_path } + end end end @@ -646,5 +654,12 @@ def apply_sorting def sanitized_sort_direction @sanitized_sort_direction ||= @index_params[:sort_direction].presence_in(["asc", :asc, "desc", :desc]) end + + def reload_frame_turbo_streams + [ + turbo_stream.turbo_frame_reload(params[:turbo_frame]), + turbo_stream.flash_alerts + ] + end end end diff --git a/app/views/avo/associations/new.html.erb b/app/views/avo/associations/new.html.erb index bffa165a7..a3375c00e 100644 --- a/app/views/avo/associations/new.html.erb +++ b/app/views/avo/associations/new.html.erb @@ -42,6 +42,7 @@ stacked: true, classes: 'w-full' %> + <%= hidden_field_tag :turbo_frame, params[:turbo_frame] %> <% end %> <% @attach_fields&.each_with_index do |field, index| %> <%= render(Avo::Items::SwitcherComponent.new( @@ -63,6 +64,9 @@ <%= a_button 'data-action': 'click->modal#close', type: :button, size: :sm, style: :outline, color: :gray do %> <%= t('avo.cancel') %> <% end %> + <%= a_button type: :submit, value: :attach_another, style: :outline, color: :green, size: :sm do %> + <%= t('avo.attach_and_attach_another') %> + <% end %> <%= a_button type: :submit, style: :primary, color: :green, size: :sm do %> <%= t('avo.attach') %> <% end %> diff --git a/spec/features/avo/fields_methods_for_views_spec.rb b/spec/features/avo/fields_methods_for_views_spec.rb index fc4b12787..833d1c79b 100644 --- a/spec/features/avo/fields_methods_for_views_spec.rb +++ b/spec/features/avo/fields_methods_for_views_spec.rb @@ -161,30 +161,5 @@ def form_fields define_method(:form_fields, original_form_fields) end end - - it "detach works using show and index fields api" do - visit "#{Avo::Engine.routes.url_helpers.resources_course_path(course)}/links?turbo_frame=has_many_field_links&view=show" - - expect { - find("tr[data-resource-id='#{course.links.first.to_param}'] [data-control='detach']").click - }.to change(course.links, :count).by(-1) - end - - it "attach works using show and index fields api" do - visit "#{Avo::Engine.routes.url_helpers.resources_course_path(course)}/links?turbo_frame=has_many_field_links&view=show" - - click_on "Attach link" - - expect(page).to have_text "Choose link" - - select attach_link.link, from: "fields_related_id" - - expect { - within '[aria-modal="true"]' do - click_on "Attach" - end - wait_for_loaded - }.to change(course.links, :count).by 1 - end end end diff --git a/spec/features/avo/has_many_field_spec.rb b/spec/features/avo/has_many_field_spec.rb index 5677a5fd5..1a04ff3f0 100644 --- a/spec/features/avo/has_many_field_spec.rb +++ b/spec/features/avo/has_many_field_spec.rb @@ -82,28 +82,6 @@ # expect(page).to have_selector("#{form} input#referrer_destroy_#{post.id}[value='/admin/resources/users/#{user.slug}/posts?turbo_frame=has_many_field_posts']", visible: false) expect(page).to have_selector("[data-component='resources-index'] #{form} button[data-control='destroy'][data-resource-id='#{post.to_param}'][data-turbo-frame='has_many_field_posts']") end - - it "deletes a post" do - visit url - - expect { - find("[data-resource-id='#{post.to_param}'] [data-control='destroy']").click - }.to change(Post, :count).by(-1) - - expect(page).to have_current_path url - expect(page).not_to have_text post.name - end - - it "detaches a post" do - visit url - - expect { - find("tr[data-resource-id='#{post.to_param}'] [data-control='detach']").click - }.to change(user.posts, :count).by(-1) - - expect(page).to have_current_path url - expect(page).not_to have_text post.name - end end end diff --git a/spec/features/avo/use_resource_spec.rb b/spec/features/avo/use_resource_spec.rb index f8fb09a72..cfc56b780 100644 --- a/spec/features/avo/use_resource_spec.rb +++ b/spec/features/avo/use_resource_spec.rb @@ -49,21 +49,6 @@ expect(page).to have_selector "[title='Delete photo comment']" end - it "if attach persist" do - visit_page - - click_on "Attach photo comment" - - expect(page).to have_text "Choose photo comment" - expect(page).to have_select "fields_related_id" - - select comment.tiny_name, from: "fields_related_id" - - click_on "Attach" - expect(page).to have_text "Photo comment attached." - expect(page).to have_text comment.tiny_name - end - it "applyes on belongs to" do visit "admin/resources/comments/#{comment.id}" diff --git a/spec/system/avo/associations_using_fields_api_spec.rb b/spec/system/avo/associations_using_fields_api_spec.rb new file mode 100644 index 000000000..cd7ec4188 --- /dev/null +++ b/spec/system/avo/associations_using_fields_api_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe "Associations using *_fields api", type: :system do + let!(:attach_link) { create :course_link } + let!(:links) { create_list :course_link, 3 } + let!(:course) { create :course, links: links } + + it "attach and detach works using show and index fields api" do + visit avo.resources_course_path(course) + + scroll_to find('turbo-frame[id="has_many_field_show_links"]') + + click_on "Attach link" + + expect(page).to have_text "Choose link" + + select attach_link.link, from: "fields_related_id" + + expect { + within '[aria-modal="true"]' do + click_on "Attach" + end + wait_for_loaded + }.to change(course.links, :count).by 1 + + expect { + accept_custom_alert do + find("tr[data-resource-id='#{course.links.first.to_param}'] [data-control='detach']").click + end + }.to change(course.links, :count).by(-1) + end +end diff --git a/spec/system/avo/attach_and_attach_another_spec.rb b/spec/system/avo/attach_and_attach_another_spec.rb new file mode 100644 index 000000000..7b28b777e --- /dev/null +++ b/spec/system/avo/attach_and_attach_another_spec.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe "Attach and atach another", type: :system do + let!(:project) { create(:project) } + let!(:comments) { create_list(:comment, 2) } + + it "attaches 2 comments without closing the modal" do + visit avo.resources_project_path(project) + + scroll_to find('turbo-frame[id="has_many_field_show_comments"]') + + click_on("Attach comment") + + select comments.first.tiny_name, from: "fields_related_id" + + expect { + within '[aria-modal="true"]' do + click_on "Attach & Attach another" + end + wait_for_loaded + }.to change(project.comments, :count).by 1 + + select comments.second.tiny_name, from: "fields_related_id" + + expect { + within '[aria-modal="true"]' do + click_on "Attach & Attach another" + end + wait_for_loaded + }.to change(project.comments, :count).by 1 + + expect(page).to have_text("Comment attached.").twice + end +end diff --git a/spec/system/avo/for_attribute_spec.rb b/spec/system/avo/for_attribute_spec.rb index 4cc73cb3c..b28728b8a 100644 --- a/spec/system/avo/for_attribute_spec.rb +++ b/spec/system/avo/for_attribute_spec.rb @@ -67,8 +67,11 @@ }.to change(project.reviews, :count).by 1 expect(current_path).to eql avo.resources_project_path(project) - expect(page).not_to have_text "Choose review" - expect(page).not_to have_text "No related record found" + + within('turbo-frame[id="has_many_field_show_reviews"]') do + expect(page).not_to have_text "Choose review" + expect(page).not_to have_text "No related record found" + end end end end diff --git a/spec/system/avo/has_many_spec.rb b/spec/system/avo/has_many_spec.rb index b0fea6131..1a8bba6b1 100644 --- a/spec/system/avo/has_many_spec.rb +++ b/spec/system/avo/has_many_spec.rb @@ -123,4 +123,39 @@ def destroy end end end + + describe "with a related post" do + let!(:post) { create :post, user: user } + let!(:url) { "/admin/resources/users/#{user.slug}?tab-group_second_tabs_group=Posts" } + + it "deletes a post" do + visit url + + scroll_to find('turbo-frame[id="has_many_field_show_posts"]') + + expect { + accept_custom_alert do + find("[data-resource-id='#{post.to_param}'] [data-control='destroy']").click + end + }.to change(Post, :count).by(-1) + + expect(page).to have_current_path url + expect(page).not_to have_text post.name + end + + it "detaches a post" do + visit url + + scroll_to find('turbo-frame[id="has_many_field_show_posts"]') + + expect { + accept_custom_alert do + find("[data-resource-id='#{post.to_param}'] [data-control='detach']").click + end + }.to change(user.posts, :count).by(-1) + + expect(page).to have_current_path url + expect(page).not_to have_text post.name + end + end end diff --git a/spec/system/avo/has_one_field_name_spec.rb b/spec/system/avo/has_one_field_name_spec.rb index 532bf0084..4e25cd4ab 100644 --- a/spec/system/avo/has_one_field_name_spec.rb +++ b/spec/system/avo/has_one_field_name_spec.rb @@ -4,13 +4,8 @@ let!(:user) { create :user } let!(:post) { create :post } - subject do - visit url - page - end - context "show" do - let(:url) { "/admin/resources/users/#{user.id}" } + let!(:url) { "/admin/resources/users/#{user.id}" } describe "without a related post" do it "attaches and detaches a post" do @@ -32,12 +27,12 @@ click_on "Attach" wait_for_loaded + expect(page).to have_text "Post attached." scroll_to second_tab_group click_tab "Main post", within_target: second_tab_group - expect(page).to have_text "Post attached." expect(page).not_to have_text "Choose post" expect(page).to have_text post.name diff --git a/spec/system/avo/use_resource_spec.rb b/spec/system/avo/use_resource_spec.rb new file mode 100644 index 000000000..58b001a38 --- /dev/null +++ b/spec/system/avo/use_resource_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe "Post comments use_resource PhotoComment", type: :system do + let!(:post) { create :post, user: admin } + let!(:comments) { create_list :comment, 20, commentable: post } + let!(:comment) { create :comment, user: admin } + + describe "tests" do + it "if attach persist" do + visit avo.resources_post_path(post) + + scroll_to find('turbo-frame[id="has_many_field_show_photo_comments"]') + + click_on "Attach photo comment" + + expect(page).to have_text "Choose photo comment" + expect(page).to have_select "fields_related_id" + + select comment.tiny_name, from: "fields_related_id" + + click_on "Attach" + expect(page).to have_text "Photo comment attached." + expect(page).to have_text comment.tiny_name + end + end +end