diff --git a/app/forms/application_form.rb b/app/forms/application_form.rb index 4438a280917..cb52b5b980f 100644 --- a/app/forms/application_form.rb +++ b/app/forms/application_form.rb @@ -39,4 +39,16 @@ class ApplicationForm < Primer::Forms::Base def url_helpers Rails.application.routes.url_helpers end + + # @return [ActiveRecord::Base] the model instance given to the form builder + def model + @builder.object + end + + # @param field_name [Symbol] the name of the attribute for which to retrieve + # the human-readable name + # @return [String] the human-readable name of the specified attribute + def attribute_name(field_name) + model.class.human_attribute_name(field_name) + end end diff --git a/app/forms/statuses/form.rb b/app/forms/statuses/form.rb new file mode 100644 index 00000000000..e454ddcc82e --- /dev/null +++ b/app/forms/statuses/form.rb @@ -0,0 +1,122 @@ +# 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 Statuses + class Form < ApplicationForm + attr_reader :submit_label + + def initialize(submit_label: nil) + super() + + @submit_label = submit_label || I18n.t(:button_save) + end + + form do |statuses_form| + statuses_form.text_field( + label: attribute_name(:name), + name: :name, + required: true, + input_width: :medium + ) + + statuses_form.text_field( + label: attribute_name(:default_done_ratio), + name: :default_done_ratio, + required: true, + type: :number, + min: 0, + max: 100, + maxlength: 7, + autocomplete: "off", + input_width: :small + ) + + statuses_form.check_box( + label: attribute_name(:is_closed), + name: :is_closed + ) + + unless already_default_status? + statuses_form.check_box( + label: attribute_name(:is_default), + name: :is_default + ) + end + + statuses_form.check_box( + label: attribute_name(:is_readonly), + name: :is_readonly, + disabled: readonly_work_packages_restricted?, + caption: I18n.t("statuses.edit.status_readonly_html").html_safe + ) + + if readonly_work_packages_restricted? + statuses_form.html_content do + angular_component_tag "opce-enterprise-banner", + inputs: { + collapsible: true, + textMessage: t("text_wp_status_read_only_html"), + moreInfoLink: OpenProject::Static::Links.links[:enterprise_docs][:status_read_only][:href] + } + end + end + + statuses_form.check_box( + label: attribute_name(:excluded_from_totals), + name: :excluded_from_totals, + caption: I18n.t("statuses.edit.status_excluded_from_totals_text") + ) + + statuses_form.color_select_list( + label: attribute_name(:color_id), + name: :color_id, + caption: I18n.t("statuses.edit.status_color_text") + ) + + statuses_form.submit( + scheme: :primary, + name: :submit, + label: submit_label + ) + end + + def status + model + end + + def already_default_status? + status.is_default_was == true + end + + def readonly_work_packages_restricted? + !EnterpriseToken.allows_to?(:readonly_work_packages) + end + end +end diff --git a/app/views/statuses/edit.html.erb b/app/views/statuses/edit.html.erb index 4aa80f1331d..8bd69c03d6f 100644 --- a/app/views/statuses/edit.html.erb +++ b/app/views/statuses/edit.html.erb @@ -39,7 +39,8 @@ See COPYRIGHT and LICENSE files for more details. end %> -<%= labelled_tabular_form_for(@status) do |f| %> - <%= render partial: 'form', locals: { f: f } %> - <%= styled_button_tag t(:button_save), class: '-primary -with-icon icon-checkmark' %> +<%= error_messages_for :status %> + +<%= primer_form_with(model: @status) do |f| %> + <%= render Statuses::Form.new(f) %> <% end %> diff --git a/app/views/statuses/new.html.erb b/app/views/statuses/new.html.erb index 8b5b660713a..417e959dd7c 100644 --- a/app/views/statuses/new.html.erb +++ b/app/views/statuses/new.html.erb @@ -39,7 +39,8 @@ See COPYRIGHT and LICENSE files for more details. end %> -<%= labelled_tabular_form_for(@status) do |f| %> - <%= render partial: 'form', locals: { f: f } %> - <%= styled_button_tag t(:button_create), class: '-primary -with-icon icon-checkmark' %> +<%= error_messages_for :status %> + +<%= primer_form_with(model: @status) do |f| %> + <%= render Statuses::Form.new(f, submit_label: I18n.t(:button_create)) %> <% end %> diff --git a/frontend/src/app/shared/components/colors/colors-autocompleter.component.ts b/frontend/src/app/shared/components/colors/colors-autocompleter.component.ts index 0f988b6c8f9..498707f5e32 100644 --- a/frontend/src/app/shared/components/colors/colors-autocompleter.component.ts +++ b/frontend/src/app/shared/components/colors/colors-autocompleter.component.ts @@ -45,6 +45,7 @@ interface ColorItem { bindLabel="name" bindValue="value" [(ngModel)]="selectedOption" + [ngClass]="classes" (change)="onModelChange($event)" [clearable]="false" appendTo="body"> @@ -66,6 +67,8 @@ export class ColorsAutocompleterComponent implements OnInit { private highlightTextInline = false; + public classes:string; + private updateInputField:HTMLInputElement|undefined; private selectedColorId:string; @@ -80,7 +83,8 @@ export class ColorsAutocompleterComponent implements OnInit { this.setColorOptions(); this.updateInputField = document.getElementsByName(this.elementRef.nativeElement.dataset.updateInput as string)[0] as HTMLInputElement|undefined; - this.highlightTextInline = JSON.parse(this.elementRef.nativeElement.dataset.highlightTextInline as string) as boolean; + this.highlightTextInline = JSON.parse(this.elementRef.nativeElement.dataset.highlightTextInline || 'false') as boolean; + this.classes = this.elementRef.nativeElement.dataset.classes || ''; } public onModelChange(color:{ name:string, value:string }) { diff --git a/lib/primer/open_project/forms/color_select.html.erb b/lib/primer/open_project/forms/color_select.html.erb new file mode 100644 index 00000000000..ba1af96a830 --- /dev/null +++ b/lib/primer/open_project/forms/color_select.html.erb @@ -0,0 +1,10 @@ +<%= render(FormControl.new(input: @input)) do %> + <%= builder.hidden_field :color_id %> + <%= angular_component_tag("opce-colors-autocompleter", + class: "colors-autocomplete form--select-container -middle", + data: { + colors:, + classes: "ng-select--primerized", + update_input: "#{builder.object_name}[color_id]" + }) %> +<% end %> diff --git a/lib/primer/open_project/forms/color_select.rb b/lib/primer/open_project/forms/color_select.rb new file mode 100644 index 00000000000..35721b81b3c --- /dev/null +++ b/lib/primer/open_project/forms/color_select.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module Primer + module OpenProject + module Forms + # :nodoc: + class ColorSelect < Primer::Forms::BaseComponent + include AngularHelper + include ColorsHelper + + delegate :builder, :form, to: :@input + + def initialize(input:) + super() + @input = input + end + + def colors + options_for_colors(builder.object) + end + end + end + end +end diff --git a/lib/primer/open_project/forms/dsl/color_select_input.rb b/lib/primer/open_project/forms/dsl/color_select_input.rb new file mode 100644 index 00000000000..754f8c9559c --- /dev/null +++ b/lib/primer/open_project/forms/dsl/color_select_input.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +module Primer + module OpenProject + module Forms + module Dsl + # :nodoc: + class ColorSelectInput < Primer::Forms::Dsl::Input + attr_reader :name, :label, :select_arguments + + def initialize(name:, label:, **system_arguments) + @name = name + @label = label + + super(**system_arguments) + end + + def to_component + ColorSelect.new(input: self) + end + + # :nocov: + def type + :color_select_list + end + # :nocov: + + # :nocov: + def focusable? + true + end + # :nocov: + 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 bfb569e38ad..e2151a300dd 100644 --- a/lib/primer/open_project/forms/dsl/input_methods.rb +++ b/lib/primer/open_project/forms/dsl/input_methods.rb @@ -25,6 +25,10 @@ module Primer add_input StorageManualProjectFolderSelectionInput.new(builder: @builder, form: @form, **) end + def color_select_list(**, &) + add_input ColorSelectInput.new(builder:, form:, **, &) + end + def html_content(**, &) add_input HtmlContentInput.new(builder: @builder, form: @form, **, &) end