Primerize statuses create/edit form

Except the color picker which still uses an angular component.

Also fixed an issue where the "Default value" checkbox could disappear
from the form after submitting with an error in the form.
This commit is contained in:
Christophe Bliard
2024-10-07 09:20:51 +02:00
parent 56bcefde2a
commit 8bd7889d1f
9 changed files with 222 additions and 7 deletions
+12
View File
@@ -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
+122
View File
@@ -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
+4 -3
View File
@@ -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 %>
+4 -3
View File
@@ -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 %>
@@ -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 }) {
@@ -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 %>
@@ -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
@@ -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
@@ -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