From 2c3a84df04f5f7906c60893df7eaa5b4a62ea074 Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Fri, 14 Nov 2025 13:24:39 +0000 Subject: [PATCH] Implement advanced check, radio form controls --- .../src/global_styles/openproject/_forms.sass | 54 +++++++ .../forms/advanced_check_box.html.erb | 26 ++++ .../open_project/forms/advanced_check_box.rb | 40 +++++ .../forms/advanced_check_box_group.html.erb | 22 +++ .../forms/advanced_check_box_group.rb | 39 +++++ .../forms/advanced_radio_button.html.erb | 26 ++++ .../forms/advanced_radio_button.rb | 40 +++++ .../advanced_radio_button_group.html.erb | 22 +++ .../forms/advanced_radio_button_group.rb | 39 +++++ .../dsl/advanced_check_box_group_input.rb | 87 +++++++++++ .../forms/dsl/advanced_check_box_input.rb | 87 +++++++++++ .../dsl/advanced_radio_button_group_input.rb | 75 +++++++++ .../forms/dsl/advanced_radio_button_input.rb | 78 ++++++++++ .../open_project/forms/dsl/input_methods.rb | 8 + .../forms/advanced_check_box_group_spec.rb | 142 ++++++++++++++++++ .../forms/advanced_radio_button_group_spec.rb | 142 ++++++++++++++++++ .../forms/dsl/input_methods_spec.rb | 14 ++ 17 files changed, 941 insertions(+) create mode 100644 lib/primer/open_project/forms/advanced_check_box.html.erb create mode 100644 lib/primer/open_project/forms/advanced_check_box.rb create mode 100644 lib/primer/open_project/forms/advanced_check_box_group.html.erb create mode 100644 lib/primer/open_project/forms/advanced_check_box_group.rb create mode 100644 lib/primer/open_project/forms/advanced_radio_button.html.erb create mode 100644 lib/primer/open_project/forms/advanced_radio_button.rb create mode 100644 lib/primer/open_project/forms/advanced_radio_button_group.html.erb create mode 100644 lib/primer/open_project/forms/advanced_radio_button_group.rb create mode 100644 lib/primer/open_project/forms/dsl/advanced_check_box_group_input.rb create mode 100644 lib/primer/open_project/forms/dsl/advanced_check_box_input.rb create mode 100644 lib/primer/open_project/forms/dsl/advanced_radio_button_group_input.rb create mode 100644 lib/primer/open_project/forms/dsl/advanced_radio_button_input.rb create mode 100644 spec/lib/primer/open_project/forms/advanced_check_box_group_spec.rb create mode 100644 spec/lib/primer/open_project/forms/advanced_radio_button_group_spec.rb diff --git a/frontend/src/global_styles/openproject/_forms.sass b/frontend/src/global_styles/openproject/_forms.sass index 38c0f64a858..17180a8c977 100644 --- a/frontend/src/global_styles/openproject/_forms.sass +++ b/frontend/src/global_styles/openproject/_forms.sass @@ -171,3 +171,57 @@ input[type="number"] &::-webkit-outer-spin-button -webkit-appearance: none margin: 0 + +.FormControl-advanced-check-group-wrap, +.FormControl-advanced-radio-group-wrap + & fieldset + padding: 0 + margin: 0 + border: 0 + +.FormControl-advanced-check-group-list, +.FormControl-advanced-radio-group-list + display: grid + grid-template-columns: repeat(2, 1fr) + gap: var(--base-size-12) var(--base-size-16) + + @media screen and (max-width: $breakpoint-sm) + grid-template-columns: 1fr + +.FormControl-advanced-checkbox-wrap, +.FormControl-advanced-radio-wrap + display: flex + background-color: var(--bgColor-inset) + border: var(--borderWidth-thin, 1px) solid var(--borderColor-default) + border-radius: var(--borderRadius-medium) + + &:has(input:hover) + background-color: var(--bgColor-accent-muted) + border-color: var(--borderColor-accent-muted) + + &:has(input:checked) + background-color: var(--bgColor-accent-muted) + border-color: var(--control-checked-borderColor-rest) + + & .FormControl-label + display: block + flex: 1 + cursor: pointer + +.FormControl-advanced-checkbox-content, +.FormControl-advanced-radio-content + display: grid + grid-template-columns: auto min-content + gap: var(--base-size-8) + padding: var(--base-size-12) + +.FormControl-advanced-checkbox-label-row, +.FormControl-advanced-radio-label-row + display: inline-grid + grid-template-columns: min-content auto + gap: var(--base-size-8) + color: var(--fgColor-accent) + +.FormControl-advanced-checkbox-icon, +.FormControl-advanced-radio-icon + fill: var(--fgColor-accent) diff --git a/lib/primer/open_project/forms/advanced_check_box.html.erb b/lib/primer/open_project/forms/advanced_check_box.html.erb new file mode 100644 index 00000000000..fe8d216ad43 --- /dev/null +++ b/lib/primer/open_project/forms/advanced_check_box.html.erb @@ -0,0 +1,26 @@ +<%= content_tag(:div, class: "FormControl-advanced-checkbox-wrap", hidden: @input.hidden?) do %> + <%= builder.label(@input.name, **@input.label_arguments) do %> +
+
+
+ <%= builder.check_box(@input.name, @input.input_arguments, checked_value, unchecked_value) %> + <%= @input.label %> +
+ <% if @input.form_control? %> +
+ <%= render(Caption.new(input: @input)) %> +
+ <% end %> +
+ <% if @input.icon.present? %> + <%= + inline_svg_tag( + @input.icon, + class: "FormControl-advanced-checkbox-icon", + aria_hidden: true + ) + %> + <% end %> +
+ <% end %> +<% end %> diff --git a/lib/primer/open_project/forms/advanced_check_box.rb b/lib/primer/open_project/forms/advanced_check_box.rb new file mode 100644 index 00000000000..6deea460eff --- /dev/null +++ b/lib/primer/open_project/forms/advanced_check_box.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module Primer + module OpenProject + module Forms + # :nodoc: + class AdvancedCheckBox < Primer::Forms::CheckBox + include InlineSvg::ActionView::Helpers + end + end + end +end diff --git a/lib/primer/open_project/forms/advanced_check_box_group.html.erb b/lib/primer/open_project/forms/advanced_check_box_group.html.erb new file mode 100644 index 00000000000..5319b650faf --- /dev/null +++ b/lib/primer/open_project/forms/advanced_check_box_group.html.erb @@ -0,0 +1,22 @@ +
+ <%= content_tag(:fieldset, **@input.input_arguments) do %> + <% if @input.label %> + <%= content_tag(:legend, **@input.label_arguments) do %> + <%= @input.label %> + <% end %> + <% end %> +
+ <%= render(Caption.new(input: @input)) %> +
+ <%= render(SpacingWrapper.new) do %> +
+ <% @input.check_boxes.each do |check_box| %> + <%= render(check_box.to_component) %> + <% end %> +
+ <% end %> + <% end %> +
+ <%= render(ValidationMessage.new(input: @input)) %> +
+
diff --git a/lib/primer/open_project/forms/advanced_check_box_group.rb b/lib/primer/open_project/forms/advanced_check_box_group.rb new file mode 100644 index 00000000000..367f5e2e348 --- /dev/null +++ b/lib/primer/open_project/forms/advanced_check_box_group.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module Primer + module OpenProject + module Forms + # :nodoc: + class AdvancedCheckBoxGroup < Primer::Forms::CheckBoxGroup + end + end + end +end diff --git a/lib/primer/open_project/forms/advanced_radio_button.html.erb b/lib/primer/open_project/forms/advanced_radio_button.html.erb new file mode 100644 index 00000000000..fd1bdb62a47 --- /dev/null +++ b/lib/primer/open_project/forms/advanced_radio_button.html.erb @@ -0,0 +1,26 @@ +<%= content_tag(:div, class: "FormControl-advanced-radio-wrap", hidden: @input.hidden?) do %> + <%= builder.label(@input.name, value: @input.value, **@input.label_arguments) do %> +
+
+
+ <%= builder.radio_button(@input.name, @input.value, **@input.input_arguments) %> + <%= @input.label %> +
+ <% if @input.form_control? %> +
+ <%= render(Caption.new(input: @input)) %> +
+ <% end %> +
+ <% if @input.icon.present? %> + <%= + inline_svg_tag( + @input.icon, + class: "FormControl-advanced-radio-icon", + aria_hidden: true + ) + %> + <% end %> +
+ <% end %> +<% end %> diff --git a/lib/primer/open_project/forms/advanced_radio_button.rb b/lib/primer/open_project/forms/advanced_radio_button.rb new file mode 100644 index 00000000000..c980970410c --- /dev/null +++ b/lib/primer/open_project/forms/advanced_radio_button.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module Primer + module OpenProject + module Forms + # :nodoc: + class AdvancedRadioButton < Primer::Forms::RadioButton + include InlineSvg::ActionView::Helpers + end + end + end +end diff --git a/lib/primer/open_project/forms/advanced_radio_button_group.html.erb b/lib/primer/open_project/forms/advanced_radio_button_group.html.erb new file mode 100644 index 00000000000..b8b563b623f --- /dev/null +++ b/lib/primer/open_project/forms/advanced_radio_button_group.html.erb @@ -0,0 +1,22 @@ +
+ <%= content_tag(:fieldset, role: "radiogroup", **@input.input_arguments) do %> + <% if @input.label %> + <%= content_tag(:legend, **@input.label_arguments) do %> + <%= @input.label %> + <% end %> + <% end %> +
+ <%= render(Caption.new(input: @input)) %> +
+ <%= render(SpacingWrapper.new) do %> +
+ <% @input.radio_buttons.each do |radio_button| %> + <%= render(radio_button.to_component) %> + <% end %> +
+ <% end %> + <% end %> +
+ <%= render(ValidationMessage.new(input: @input)) %> +
+
diff --git a/lib/primer/open_project/forms/advanced_radio_button_group.rb b/lib/primer/open_project/forms/advanced_radio_button_group.rb new file mode 100644 index 00000000000..f4f76b8f067 --- /dev/null +++ b/lib/primer/open_project/forms/advanced_radio_button_group.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module Primer + module OpenProject + module Forms + # :nodoc: + class AdvancedRadioButtonGroup < Primer::Forms::RadioButtonGroup + end + end + end +end diff --git a/lib/primer/open_project/forms/dsl/advanced_check_box_group_input.rb b/lib/primer/open_project/forms/dsl/advanced_check_box_group_input.rb new file mode 100644 index 00000000000..3a9d6eeaafa --- /dev/null +++ b/lib/primer/open_project/forms/dsl/advanced_check_box_group_input.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module Primer + module OpenProject + module Forms + module Dsl + # :nodoc: + class AdvancedCheckBoxGroupInput < Primer::Forms::Dsl::Input + attr_reader :name, :label, :check_boxes + + def initialize(name: nil, label: nil, **system_arguments) + @name = name + @label = label + @check_boxes = [] + + super(**system_arguments) + + yield(self) if block_given? + end + + def to_component + AdvancedCheckBoxGroup.new(input: self) + end + + def type + :check_box_group + end + + def focusable? + true + end + + def autofocus! + @check_boxes.first&.autofocus! + end + + def check_box(**system_arguments, &) + args = { + name: @name, + builder: @builder, + form: @form, + scheme: scheme, + disabled: disabled?, + **system_arguments + } + + @check_boxes << AdvancedCheckBoxInput.new(**args, &) + end + + private + + def scheme + @name ? :array : :boolean + end + end + end + end + end +end diff --git a/lib/primer/open_project/forms/dsl/advanced_check_box_input.rb b/lib/primer/open_project/forms/dsl/advanced_check_box_input.rb new file mode 100644 index 00000000000..50e106b3a96 --- /dev/null +++ b/lib/primer/open_project/forms/dsl/advanced_check_box_input.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module Primer + module OpenProject + module Forms + module Dsl + # :nodoc: + class AdvancedCheckBoxInput < Primer::Forms::Dsl::Input + DEFAULT_SCHEME = :boolean + SCHEMES = [DEFAULT_SCHEME, :array].freeze + + attr_reader :name, :label, :value, :unchecked_value, :scheme, :icon + + def initialize(name:, label:, value: nil, unchecked_value: nil, scheme: DEFAULT_SCHEME, icon: nil, **system_arguments) + raise ArgumentError, "Check box scheme must be one of #{SCHEMES.join(', ')}" unless SCHEMES.include?(scheme) + + raise ArgumentError, "Check box needs an explicit value if scheme is array" if scheme == :array && value.nil? + + @name = name + @label = label + @value = value + @unchecked_value = unchecked_value + @scheme = scheme + @icon = icon + + super(**system_arguments) + + yield(self) if block_given? + end + + # check boxes cannot be invalid, as both checked and unchecked are valid states + # :nocov: + def valid? + true + end + # :nocov: + + def to_component + AdvancedCheckBox.new(input: self) + end + + def type + :check_box + end + + def supports_validation? + false + end + + def values_disambiguate_template_names? + # Check boxes submitted as an array all have the same name, so we return true here + # to ensure different caption templates can be attached to individual check box inputs. + @scheme == :array + end + end + end + end + end +end diff --git a/lib/primer/open_project/forms/dsl/advanced_radio_button_group_input.rb b/lib/primer/open_project/forms/dsl/advanced_radio_button_group_input.rb new file mode 100644 index 00000000000..66f6a547326 --- /dev/null +++ b/lib/primer/open_project/forms/dsl/advanced_radio_button_group_input.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module Primer + module OpenProject + module Forms + module Dsl + # :nodoc: + class AdvancedRadioButtonGroupInput < Primer::Forms::Dsl::Input + attr_reader :name, :label, :radio_buttons + + def initialize(name:, label: nil, **system_arguments) + @name = name + @label = label + @radio_buttons = [] + + super(**system_arguments) + + yield(self) if block_given? + end + + def to_component + AdvancedRadioButtonGroup.new(input: self) + end + + def type + :radio_button_group + end + + def autofocus! + @radio_buttons.first&.autofocus! + end + + def focusable? + true + end + + def radio_button(**system_arguments, &) + @radio_buttons << AdvancedRadioButtonInput.new( + builder: @builder, form: @form, name: @name, disabled: disabled?, + **system_arguments, & + ) + end + end + end + end + end +end diff --git a/lib/primer/open_project/forms/dsl/advanced_radio_button_input.rb b/lib/primer/open_project/forms/dsl/advanced_radio_button_input.rb new file mode 100644 index 00000000000..766826e2149 --- /dev/null +++ b/lib/primer/open_project/forms/dsl/advanced_radio_button_input.rb @@ -0,0 +1,78 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ + +module Primer + module OpenProject + module Forms + module Dsl + # :nodoc: + class AdvancedRadioButtonInput < Primer::Forms::Dsl::Input + attr_reader :name, :value, :label, :icon + + def initialize(name:, value:, label:, icon: nil, **system_arguments) + @name = name + @value = value + @label = label + @icon = icon + + super(**system_arguments) + + yield(self) if block_given? + end + + # radio buttons cannot be invalid, as both selected and unselected are valid states + # :nocov: + def valid? + true + end + # :nocov: + + def to_component + AdvancedRadioButton.new(input: self) + end + + # :nocov: + def type + :radio_button + end + # :nocov: + + def supports_validation? + false + end + + def values_disambiguate_template_names? + true + end + end + end + end + end +end diff --git a/lib/primer/open_project/forms/dsl/input_methods.rb b/lib/primer/open_project/forms/dsl/input_methods.rb index 7ca247fafb9..7c217c9e2c7 100644 --- a/lib/primer/open_project/forms/dsl/input_methods.rb +++ b/lib/primer/open_project/forms/dsl/input_methods.rb @@ -21,6 +21,14 @@ module Primer super(**decorate_options(**), &) end + def advanced_radio_button_group(**, &) + add_input AdvancedRadioButtonGroupInput.new(builder:, form:, **decorate_options(**), &) + end + + def advanced_check_box_group(**, &) + add_input AdvancedCheckBoxGroupInput.new(builder:, form:, **decorate_options(**), &) + end + def autocompleter(**, &) add_input AutocompleterInput.new(builder:, form:, **decorate_options(**), &) end diff --git a/spec/lib/primer/open_project/forms/advanced_check_box_group_spec.rb b/spec/lib/primer/open_project/forms/advanced_check_box_group_spec.rb new file mode 100644 index 00000000000..316f458f0f5 --- /dev/null +++ b/spec/lib/primer/open_project/forms/advanced_check_box_group_spec.rb @@ -0,0 +1,142 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ +# +require "spec_helper" + +RSpec.describe Primer::OpenProject::Forms::AdvancedCheckBoxGroup, type: :forms do + include ViewComponent::TestHelpers + + describe "rendering" do + let(:params) { {} } + let(:model) { build_stubbed(:comment) } + + def render_form + render_in_view_context(model, params) do |model, params| + primer_form_with(url: "/foo", model:) do |f| + render_inline_form(f) do |check_form| + check_form.advanced_check_box_group( + name: :ultimate_answer, + label: "Ultimate answer", + **params + ) do |group| + group.check_box( + value: "one", + label: "One", + caption: "Pick me", + icon: "icon_logo.svg" + ) + group.check_box( + value: "two", + label: "Two", + caption: "Don't pick me", + icon: "icon_logo.svg" + ) + group.check_box( + value: "three", + label: "Three", + icon: nil + ) + end + end + end + end + end + + subject(:rendered_form) do + render_form + page + end + + it "renders the fieldset" do + expect(rendered_form).to have_selector :fieldset, "Ultimate answer" + end + + it "renders the checkboxes", :aggregate_failures do + expect(rendered_form).to have_field "One", type: :checkbox, fieldset: "Ultimate answer" + expect(rendered_form).to have_field "Two", type: :checkbox, fieldset: "Ultimate answer" + expect(rendered_form).to have_field "Three", type: :checkbox, fieldset: "Ultimate answer" + end + + it "renders icons" do + expect(rendered_form).to have_element :svg, count: 2, aria: { hidden: true } + end + + it "renders captions", :aggregate_failures do + expect(rendered_form).to have_css ".FormControl-caption", count: 2 + expect(rendered_form).to have_css ".FormControl-caption", text: "Pick me" + expect(rendered_form).to have_css ".FormControl-caption", text: "Don't pick me" + end + end + + describe "standard checkbox group compatibility" do + specify "hidden checkbox group", :aggregate_failures do + render_in_view_context do + primer_form_with(url: "/foo") do |f| + render_inline_form(f) do |check_form| + check_form.advanced_check_box_group(label: "Foobar", hidden: true) do |check_group| + check_group.check_box(name: :foo, label: "Foo") + end + end + end + end + + expect(page).to have_selector :fieldset, visible: :hidden + expect(page).to have_css ".FormControl-advanced-checkbox-wrap", visible: :hidden + end + + specify "disabled checkbox group disables constituent checkboxes" do + render_in_view_context do + primer_form_with(url: "/foo") do |f| + render_inline_form(f) do |check_form| + check_form.advanced_check_box_group(label: "Foobar", disabled: true) do |check_group| + check_group.check_box(name: :foo, label: "Foo") + end + end + end + end + + expect(page).to have_css ".FormControl-advanced-checkbox-wrap input[disabled]" + end + + specify "checkbox can be individually disabled in group" do + render_in_view_context do + primer_form_with(url: "/foo") do |f| + render_inline_form(f) do |check_form| + check_form.advanced_check_box_group(label: "Foobar") do |check_group| + check_group.check_box(name: :foo, label: "Foo", disabled: true) + end + end + end + end + + expect(page).to have_css ".FormControl-advanced-checkbox-wrap input[disabled]" + end + end +end diff --git a/spec/lib/primer/open_project/forms/advanced_radio_button_group_spec.rb b/spec/lib/primer/open_project/forms/advanced_radio_button_group_spec.rb new file mode 100644 index 00000000000..19b5ece9cca --- /dev/null +++ b/spec/lib/primer/open_project/forms/advanced_radio_button_group_spec.rb @@ -0,0 +1,142 @@ +# frozen_string_literal: true + +#-- copyright +# OpenProject is an open source project management software. +# Copyright (C) the OpenProject GmbH +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See COPYRIGHT and LICENSE files for more details. +#++ +# +require "spec_helper" + +RSpec.describe Primer::OpenProject::Forms::AdvancedRadioButtonGroup, type: :forms do + include ViewComponent::TestHelpers + + describe "rendering" do + let(:params) { {} } + let(:model) { build_stubbed(:comment) } + + def render_form + render_in_view_context(model, params) do |model, params| + primer_form_with(url: "/foo", model:) do |f| + render_inline_form(f) do |radio_form| + radio_form.advanced_radio_button_group( + name: :ultimate_answer, + label: "Ultimate answer", + **params + ) do |group| + group.radio_button( + value: "one", + label: "One", + caption: "Pick me", + icon: "icon_logo.svg" + ) + group.radio_button( + value: "two", + label: "Two", + caption: "Don't pick me", + icon: "icon_logo.svg" + ) + group.radio_button( + value: "three", + label: "Three", + icon: nil + ) + end + end + end + end + end + + subject(:rendered_form) do + render_form + page + end + + it "renders the fieldset" do + expect(rendered_form).to have_selector :fieldset, "Ultimate answer", role: "radiogroup" + end + + it "renders the radio buttons", :aggregate_failures do + expect(rendered_form).to have_field "One", type: :radio, fieldset: "Ultimate answer" + expect(rendered_form).to have_field "Two", type: :radio, fieldset: "Ultimate answer" + expect(rendered_form).to have_field "Three", type: :radio, fieldset: "Ultimate answer" + end + + it "renders icons" do + expect(rendered_form).to have_element :svg, count: 2, aria: { hidden: true } + end + + it "renders captions", :aggregate_failures do + expect(rendered_form).to have_css ".FormControl-caption", count: 2 + expect(rendered_form).to have_css ".FormControl-caption", text: "Pick me" + expect(rendered_form).to have_css ".FormControl-caption", text: "Don't pick me" + end + end + + describe "standard radio button group compatibility" do + specify "hidden radio button group", :aggregate_failures do + render_in_view_context do + primer_form_with(url: "/foo") do |f| + render_inline_form(f) do |radio_form| + radio_form.advanced_radio_button_group(name: :foobar, label: "Foobar", hidden: true) do |radio_group| + radio_group.radio_button(name: :foo, value: "Foo", label: "Foo") + end + end + end + end + + expect(page).to have_selector :fieldset, visible: :hidden + expect(page).to have_css ".FormControl-advanced-radio-wrap", visible: :hidden + end + + specify "disabled radio group disables constituent radios" do + render_in_view_context do + primer_form_with(url: "/foo") do |f| + render_inline_form(f) do |radio_form| + radio_form.advanced_radio_button_group(name: :foobar, label: "Foobar", disabled: true) do |radio_group| + radio_group.radio_button(name: :foo, value: "Foo", label: "Foo") + end + end + end + end + + expect(page).to have_css ".FormControl-advanced-radio-wrap input[disabled]" + end + + specify "radio can be individually disabled in group" do + render_in_view_context do + primer_form_with(url: "/foo") do |f| + render_inline_form(f) do |radio_form| + radio_form.advanced_radio_button_group(name: :foobar, label: "Foobar") do |radio_group| + radio_group.radio_button(name: :foo, value: "Foo", label: "Foo", disabled: true) + end + end + end + end + + expect(page).to have_css ".FormControl-advanced-radio-wrap input[disabled]" + end + end +end diff --git a/spec/lib/primer/open_project/forms/dsl/input_methods_spec.rb b/spec/lib/primer/open_project/forms/dsl/input_methods_spec.rb index 1b63d4e8a9f..c12ed3c3fd3 100644 --- a/spec/lib/primer/open_project/forms/dsl/input_methods_spec.rb +++ b/spec/lib/primer/open_project/forms/dsl/input_methods_spec.rb @@ -113,6 +113,20 @@ RSpec.describe Primer::OpenProject::Forms::Dsl::InputMethods, type: :forms do include_examples "input class", Primer::Forms::Dsl::CheckBoxGroupInput it_behaves_like "supporting help texts" end + + describe "#advanced_radio_button_group" do + let(:field_group) { form_dsl.advanced_radio_button_group(name:, label:, **options) } + + include_examples "input class", Primer::OpenProject::Forms::Dsl::AdvancedRadioButtonGroupInput + it_behaves_like "supporting help texts" + end + + describe "#advanced_check_box_group" do + let(:field_group) { form_dsl.advanced_check_box_group(name:, label:, **options) } + + include_examples "input class", Primer::OpenProject::Forms::Dsl::AdvancedCheckBoxGroupInput + it_behaves_like "supporting help texts" + end end describe "#separator" do