diff --git a/app/helpers/ui_helper.rb b/app/helpers/ui_helper.rb index 53d9556bd5..32325d9232 100644 --- a/app/helpers/ui_helper.rb +++ b/app/helpers/ui_helper.rb @@ -107,7 +107,13 @@ def js_button(options = {}, properties = {}) def modal_button_to(target_id, options = {}) properties = { data: { "bs-toggle": "modal" } } - _link_to target_id, { icon: "dot-circle-o", type: "outline-primary", text: "Set 'text' option", size: "md" }.merge(options), properties + options = { icon: "dot-circle-o", type: "outline-primary", text: "Set 'text' option", size: "md" }.merge(options) + # A modal-toggle button only opens a Bootstrap modal client-side; it never navigates or + # submits a form. rails-ujs' `data-disable-with` disables the link on click and only re-enables + # it on the next page load, so without opting out the button stays stuck showing "Please wait..." + # after the modal is dismissed (see #5632). + options[:data] = { disable_with: nil }.merge(options[:data] || {}) + _link_to target_id, options, properties end def new_button_to(link, options = {}) diff --git a/spec/helpers/ui_helper_spec.rb b/spec/helpers/ui_helper_spec.rb index 1ada45de70..35e1a96359 100644 --- a/spec/helpers/ui_helper_spec.rb +++ b/spec/helpers/ui_helper_spec.rb @@ -137,5 +137,38 @@ end end end -end + describe 'modal_button_to' do + context 'with default options' do + subject { helper.modal_button_to("#newRequest", text: "New Quantity Request", icon: "plus", type: "success") } + + it 'renders a link that toggles the Bootstrap modal' do + button = Nokogiri::HTML(subject).css("a").first + expect(button).to_not be_nil + expect(button.attributes["href"].value).to eq("#newRequest") + expect(button.attributes["data-bs-toggle"].value).to eq("modal") + expect(button.attributes["class"].value).to include("btn btn-success") + expect(button.text.strip).to eq("New Quantity Request") + end + + # Regression test for #5632: a modal-toggle button never navigates, so it must not carry + # rails-ujs' `data-disable-with` attribute, otherwise it stays stuck on "Please wait..." + # after the modal is dismissed. + it 'does not set data-disable-with' do + button = Nokogiri::HTML(subject).css("a").first + expect(button.attributes["data-disable-with"]).to be_nil + end + end + + context 'when the caller passes custom data' do + subject { helper.modal_button_to("#newRequest", text: "New Quantity Request", data: {test: "test"}) } + + it 'keeps the custom data and still omits data-disable-with' do + button = Nokogiri::HTML(subject).css("a").first + expect(button.attributes["data-test"].value).to eq("test") + expect(button.attributes["data-bs-toggle"].value).to eq("modal") + expect(button.attributes["data-disable-with"]).to be_nil + end + end + end +end diff --git a/spec/system/request_system_spec.rb b/spec/system/request_system_spec.rb index c1d3c936b9..375bb65189 100644 --- a/spec/system/request_system_spec.rb +++ b/spec/system/request_system_spec.rb @@ -143,6 +143,15 @@ expect(page).to have_select("partner_id", with_options: partner_names) end + it "keeps its label after the modal is dismissed" do + expect(page).to have_select("partner_id") + within("#newRequest") { find("button[aria-label='Close']").click } + + trigger = find("a[href='#newRequest']") + expect(trigger).to have_text("New Quantity Request") + expect(trigger).to have_no_text("Please wait...") + end + context "selecting a partner" do it "redirects to new partner request page" do select(partner1.name, from: "partner_id")