mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 %>
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user