Skip to content

Commit 41915ca

Browse files
committed
Register custom fields for inplace editing and add more field types
1 parent 85e9e6e commit 41915ca

File tree

17 files changed

+502
-58
lines changed

17 files changed

+502
-58
lines changed

app/components/open_project/common/inplace_edit_field_component.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ def initialize(model:, attribute:, enforce_edit_mode: false, **system_arguments)
4242
@enforce_edit_mode = enforce_edit_mode
4343
@system_arguments = system_arguments
4444
@system_arguments[:id] = system_arguments[:id] || SecureRandom.uuid
45+
@system_arguments[:required] ||= required?
46+
@system_arguments[:label] ||= field_label
4547
end
4648

4749
def field_class
@@ -93,6 +95,37 @@ def writable?
9395
false
9496
end
9597
end
98+
99+
def field_label
100+
# Check if this is a custom field attribute
101+
if attribute.to_s.start_with?("custom_field_") && custom_field
102+
return custom_field.name
103+
end
104+
105+
label = model.class.human_attribute_name(attribute)
106+
label = label.titleize if attribute.to_s.include?("_")
107+
label
108+
end
109+
110+
def required?
111+
return @required if instance_variable_defined?(:@required)
112+
113+
@required = if @system_arguments.key?(:required)
114+
@system_arguments[:required]
115+
elsif attribute.to_s.start_with?("custom_field_")
116+
# For custom fields, check the is_required attribute
117+
custom_field&.is_required || false
118+
else
119+
# For regular model attributes, check ActiveRecord validations
120+
model.class.validators_on(attribute).any?(ActiveRecord::Validations::PresenceValidator)
121+
end
122+
end
123+
124+
def custom_field
125+
return @custom_field if defined?(@custom_field)
126+
127+
@custom_field = CustomField.find_by(id: attribute.to_s.sub("custom_field_", "").to_i)
128+
end
96129
end
97130
end
98131
end
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
module OpenProject
32+
module Common
33+
module InplaceEditFields
34+
class BooleanInputComponent < ViewComponent::Base
35+
attr_reader :form, :attribute, :model
36+
37+
def self.display_class
38+
DisplayFields::DisplayFieldComponent
39+
end
40+
41+
def initialize(form:, attribute:, model:, **system_arguments)
42+
super()
43+
@form = form
44+
@attribute = attribute
45+
@model = model
46+
@system_arguments = system_arguments
47+
@system_arguments[:classes] = class_names(
48+
@system_arguments[:classes],
49+
"op-inplace-edit-field--boolean"
50+
)
51+
@system_arguments[:label] ||= model.class.human_attribute_name(attribute)
52+
end
53+
54+
def call
55+
form.check_box name: attribute,
56+
data: { controller: "inplace-edit",
57+
action: "click->inplace-edit#submitForm" },
58+
**@system_arguments
59+
end
60+
61+
private
62+
63+
def submit_url
64+
inplace_edit_field_submit_path(
65+
model: model.class.name,
66+
id: model.id,
67+
attribute:,
68+
system_arguments_json: @system_arguments.to_json
69+
)
70+
end
71+
end
72+
end
73+
end
74+
end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
module OpenProject
32+
module Common
33+
module InplaceEditFields
34+
class CalculatedValueInputComponent < InplaceEditFields::TextInputComponent
35+
def initialize(form:, attribute:, model:, **system_arguments)
36+
system_arguments[:readonly] = true
37+
super
38+
end
39+
end
40+
end
41+
end
42+
end
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
module OpenProject
32+
module Common
33+
module InplaceEditFields
34+
class DateInputComponent < InplaceEditFields::TextInputComponent
35+
def initialize(form:, attribute:, model:, **system_arguments)
36+
system_arguments[:type] = :date
37+
super
38+
end
39+
end
40+
end
41+
end
42+
end
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<%=
2+
flex_layout(
3+
align_items: :flex_start,
4+
justify_content: :space_between
5+
) do |flex|
6+
flex.with_row(mb: 1) do
7+
render OpenProject::Common::AttributeLabelComponent.new(
8+
attribute:,
9+
model:,
10+
required: @system_arguments[:required],
11+
hidden: @system_arguments[:visually_hide_label]
12+
) do
13+
render(Primer::Beta::Text.new(font_weight: :bold)) { @system_arguments[:label] }
14+
end
15+
end
16+
17+
flex.with_row(w: :full) do
18+
input_specific_call
19+
end
20+
21+
flex.with_row(w: :full) do
22+
render OpenProject::Common::AttributeHelpTextCaptionComponent.new(
23+
help_text: helpers.help_text_for(
24+
model,
25+
attribute,
26+
current_user: helpers.current_user
27+
)
28+
)
29+
end
30+
end
31+
%>

app/components/open_project/common/inplace_edit_fields/display_fields/display_field_component.rb

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ module Common
3333
module InplaceEditFields
3434
module DisplayFields
3535
class DisplayFieldComponent < ViewComponent::Base
36-
include OpenProject::TextFormatting
36+
include OpPrimer::ComponentHelpers
3737

3838
attr_reader :model, :attribute, :writable
3939

@@ -48,25 +48,27 @@ def initialize(model:, attribute:, writable:, **system_arguments)
4848
def render_display_value
4949
value = model.public_send(attribute)
5050

51-
if value.present?
52-
format_text(value)
51+
if value.is_a?(TrueClass) || value.is_a?(FalseClass)
52+
boolean_display_value(value)
53+
elsif value.present?
54+
value.to_s
5355
else
54-
"–"
56+
t("placeholders.default")
5557
end
5658
end
5759

5860
def display_field_arguments
5961
@display_field_arguments ||= {
60-
classes: "op-inplace-edit--display-field #{'op-inplace-edit--display-field_editable' if writable}",
62+
classes: "op-inplace-edit--display-field #{'op-inplace-edit--display-field_editable' if writable?}",
6163
data: {
6264
controller: "inplace-edit",
6365
inplace_edit_url_value: edit_url,
64-
action: writable ? "click->inplace-edit#request" : ""
66+
action: writable? ? "click->inplace-edit#request" : ""
6567
}
6668
}
6769
end
6870

69-
def call
71+
def input_specific_call
7072
render(Primer::BaseComponent.new(tag: :div, **display_field_arguments)) do
7173
render_display_value
7274
end
@@ -82,6 +84,14 @@ def edit_url
8284
system_arguments_json: @system_arguments.to_json
8385
)
8486
end
87+
88+
def boolean_display_value(value)
89+
I18n.t("general_text_#{value ? 'yes' : 'no'}")
90+
end
91+
92+
def writable?
93+
writable && (@system_arguments[:readonly].nil? || @system_arguments[:readonly] == false)
94+
end
8595
end
8696
end
8797
end
Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
.op-inplace-edit
22
&--display-field
3-
&_editable
4-
margin-left: -9px !important // cancel out 8px padding + 1px border
5-
margin-right: -9px !important // cancel out 8px padding + 1px border
6-
padding: var(--base-size-8)
7-
width: calc(100% + 18px) !important
8-
border: 1px solid transparent
9-
border-radius: var(--borderRadius-medium)
3+
padding: var(--base-size-4) var(--base-size-8)
4+
border: 1px solid transparent
5+
border-radius: var(--borderRadius-medium)
106

11-
&:hover, &:focus
12-
border-color: var(--borderColor-default)
13-
box-shadow: var(--shadow-inset)
7+
&:hover, &:focus
8+
border-color: var(--borderColor-default)
9+
box-shadow: var(--shadow-inset)
1410

1511
&:not(&_editable)
1612
cursor: not-allowed

app/components/open_project/common/inplace_edit_fields/display_fields/rich_text_area_component.rb

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,28 @@ module Common
3333
module InplaceEditFields
3434
module DisplayFields
3535
class RichTextAreaComponent < DisplayFieldComponent
36+
include OpenProject::TextFormatting
37+
3638
attr_reader :model, :attribute, :writable
3739

38-
def call
40+
def input_specific_call
3941
render(Primer::BaseComponent.new(tag: :div, **display_field_arguments)) do
4042
render(Primer::BaseComponent.new(tag: :div,
4143
classes: "op-uc-container op-uc-container_reduced-headings -multiline")) do
4244
render_display_value
4345
end
4446
end
4547
end
48+
49+
def render_display_value
50+
value = model.public_send(attribute)
51+
52+
if value.present?
53+
format_text(value)
54+
else
55+
t("placeholders.default")
56+
end
57+
end
4658
end
4759
end
4860
end
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# frozen_string_literal: true
2+
3+
#-- copyright
4+
# OpenProject is an open source project management software.
5+
# Copyright (C) the OpenProject GmbH
6+
#
7+
# This program is free software; you can redistribute it and/or
8+
# modify it under the terms of the GNU General Public License version 3.
9+
#
10+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
11+
# Copyright (C) 2006-2013 Jean-Philippe Lang
12+
# Copyright (C) 2010-2013 the ChiliProject Team
13+
#
14+
# This program is free software; you can redistribute it and/or
15+
# modify it under the terms of the GNU General Public License
16+
# as published by the Free Software Foundation; either version 2
17+
# of the License, or (at your option) any later version.
18+
#
19+
# This program is distributed in the hope that it will be useful,
20+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
# GNU General Public License for more details.
23+
#
24+
# You should have received a copy of the GNU General Public License
25+
# along with this program; if not, write to the Free Software
26+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27+
#
28+
# See COPYRIGHT and LICENSE files for more details.
29+
#++
30+
31+
module OpenProject
32+
module Common
33+
module InplaceEditFields
34+
class FloatInputComponent < InplaceEditFields::TextInputComponent
35+
def initialize(form:, attribute:, model:, **system_arguments)
36+
system_arguments[:type] = :number
37+
system_arguments[:step] = "any"
38+
super
39+
end
40+
end
41+
end
42+
end
43+
end

0 commit comments

Comments
 (0)