chobble-forms 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/chobble_forms/field_utils.rb +12 -9
- data/lib/chobble_forms/helpers.rb +64 -28
- data/lib/chobble_forms/version.rb +1 -1
- data/views/chobble_forms/_form_context.html.erb +6 -0
- data/views/chobble_forms/_pass_fail_comment.html.erb +4 -3
- data/views/chobble_forms/_pass_fail_na_comment.html.erb +4 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 771171d582d4bdb09d03fc7ac56a37ca4922d7ce9ee76f392c19c0667e2cd6d3
|
4
|
+
data.tar.gz: e692e2d66579f14eae1099989efddef5a7358620653ac6ab7daaf3ffab151333
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7b53bd70bfa1063f24071b476a9789b43d79c0c539e033857b1331caf0456bb324fea113a93471bc0fef9b114c9b9004f52b10c0c3a82ef52c6a85e54b91e34
|
7
|
+
data.tar.gz: f4b9fd0dedb8a2e0d133cf09f0dc0ab5e9e4b390cfeafe510b16424e9ec1037492fdec506db580447c61d6857597bb164d60c2b211fc019f1df58d1472f27202
|
@@ -7,23 +7,21 @@ module ChobbleForms
|
|
7
7
|
module FieldUtils
|
8
8
|
extend T::Sig
|
9
9
|
|
10
|
-
sig { params(field: Symbol).returns(
|
10
|
+
sig { params(field: Symbol).returns(Symbol) }
|
11
11
|
def self.strip_field_suffix(field)
|
12
|
-
field.to_s.gsub(/_pass$|_comment$/, "")
|
12
|
+
field.to_s.gsub(/_pass$|_comment$/, "").to_sym
|
13
13
|
end
|
14
14
|
|
15
|
-
sig { params(field: Symbol, partial: Symbol).returns(T::Array[
|
15
|
+
sig { params(field: Symbol, partial: Symbol).returns(T::Array[Symbol]) }
|
16
16
|
def self.get_composite_fields(field, partial)
|
17
|
-
fields = T.let([], T::Array[
|
17
|
+
fields = T.let([], T::Array[Symbol])
|
18
18
|
partial_str = partial.to_s
|
19
19
|
|
20
|
-
if partial_str.include?("pass_fail") && !field.to_s.end_with?("_pass")
|
21
|
-
fields << "#{field}_pass"
|
22
|
-
end
|
20
|
+
fields << :"#{field}_pass" if partial_str.include?("pass_fail") && !field.to_s.end_with?("_pass")
|
23
21
|
|
24
22
|
if partial_str.include?("comment")
|
25
23
|
base = field.to_s.end_with?("_pass") ? strip_field_suffix(field) : field
|
26
|
-
fields << "#{base}_comment"
|
24
|
+
fields << :"#{base}_comment"
|
27
25
|
end
|
28
26
|
|
29
27
|
fields
|
@@ -44,7 +42,7 @@ module ChobbleForms
|
|
44
42
|
is_pass_field?(field) || is_comment_field?(field)
|
45
43
|
end
|
46
44
|
|
47
|
-
sig { params(field: Symbol).returns(
|
45
|
+
sig { params(field: Symbol).returns(Symbol) }
|
48
46
|
def self.base_field_name(field)
|
49
47
|
strip_field_suffix(field)
|
50
48
|
end
|
@@ -53,5 +51,10 @@ module ChobbleForms
|
|
53
51
|
def self.form_field_label(form, field)
|
54
52
|
I18n.t("forms.#{form}.fields.#{field}")
|
55
53
|
end
|
54
|
+
|
55
|
+
sig { params(assessment_key: Symbol).returns(Symbol) }
|
56
|
+
def self.form_name_from_assessment(assessment_key)
|
57
|
+
assessment_key.to_s.gsub(/_assessment$/, "").to_sym
|
58
|
+
end
|
56
59
|
end
|
57
60
|
end
|
@@ -7,7 +7,35 @@ module ChobbleForms
|
|
7
7
|
module Helpers
|
8
8
|
extend T::Sig
|
9
9
|
|
10
|
-
|
10
|
+
SelectOption = T.type_alias {
|
11
|
+
[String, T.any(String, Integer)]
|
12
|
+
}
|
13
|
+
|
14
|
+
LocalAssignValue = T.type_alias {
|
15
|
+
T.any(
|
16
|
+
String,
|
17
|
+
Symbol,
|
18
|
+
Integer,
|
19
|
+
Float,
|
20
|
+
T::Boolean,
|
21
|
+
T::Array[SelectOption],
|
22
|
+
T::Hash[Symbol, T.untyped]
|
23
|
+
)
|
24
|
+
}
|
25
|
+
|
26
|
+
FieldSetupResult = T.type_alias {
|
27
|
+
{
|
28
|
+
form_object: T.untyped,
|
29
|
+
i18n_base: String,
|
30
|
+
value: T.untyped,
|
31
|
+
prefilled: T::Boolean,
|
32
|
+
field_label: String,
|
33
|
+
field_hint: T.nilable(String),
|
34
|
+
field_placeholder: T.nilable(String)
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
sig { params(field: Symbol, local_assigns: T::Hash[Symbol, LocalAssignValue]).returns(FieldSetupResult) }
|
11
39
|
def form_field_setup(field, local_assigns)
|
12
40
|
validate_local_assigns(local_assigns)
|
13
41
|
validate_form_context
|
@@ -22,6 +50,7 @@ module ChobbleForms
|
|
22
50
|
sig { params(form_object: T.untyped, field: Symbol).returns([T.untyped, T::Boolean]) }
|
23
51
|
def get_field_value_and_prefilled_status(form_object, field)
|
24
52
|
return [nil, false] unless form_object&.object
|
53
|
+
|
25
54
|
model = form_object.object
|
26
55
|
resolved = resolve_field_value(model, field)
|
27
56
|
[resolved[:value], resolved[:prefilled]]
|
@@ -30,6 +59,7 @@ module ChobbleForms
|
|
30
59
|
sig { params(form: T.untyped, comment_field: Symbol, base_field_label: String).returns(T::Hash[Symbol, T.untyped]) }
|
31
60
|
def comment_field_options(form, comment_field, base_field_label)
|
32
61
|
raise ArgumentError, "form_object required" unless form
|
62
|
+
|
33
63
|
model = form.object
|
34
64
|
|
35
65
|
comment_value, comment_prefilled =
|
@@ -81,21 +111,16 @@ module ChobbleForms
|
|
81
111
|
rows
|
82
112
|
step
|
83
113
|
type
|
84
|
-
], T::Array[Symbol])
|
114
|
+
].freeze, T::Array[Symbol])
|
85
115
|
|
86
|
-
sig { params(local_assigns: T::Hash[Symbol,
|
116
|
+
sig { params(local_assigns: T::Hash[Symbol, LocalAssignValue]).void }
|
87
117
|
def validate_local_assigns(local_assigns)
|
88
|
-
if local_assigns[:field]&.respond_to?(:to_s) &&
|
89
|
-
local_assigns[:field].to_s.match?(/^[A-Z]/)
|
90
|
-
raise ArgumentError, "Field names must be snake_case symbols, not class names. Use :field, not Field."
|
91
|
-
end
|
92
|
-
|
93
118
|
locally_assigned_keys = local_assigns.keys
|
94
119
|
disallowed_keys = locally_assigned_keys - ALLOWED_LOCAL_ASSIGNS
|
95
120
|
|
96
|
-
|
97
|
-
|
98
|
-
|
121
|
+
return unless disallowed_keys.any?
|
122
|
+
|
123
|
+
raise ArgumentError, "local_assigns contains #{disallowed_keys.inspect}"
|
99
124
|
end
|
100
125
|
|
101
126
|
sig { void }
|
@@ -109,7 +134,10 @@ module ChobbleForms
|
|
109
134
|
sig { params(field: Symbol).returns(T::Hash[Symbol, T.nilable(String)]) }
|
110
135
|
def build_field_translations(field)
|
111
136
|
i18n_base = T.unsafe(instance_variable_get(:@_current_i18n_base))
|
112
|
-
|
137
|
+
|
138
|
+
# Only strip _pass suffix for pass/fail fields, not _comment fields
|
139
|
+
lookup_field = field.to_s.end_with?("_pass") ? FieldUtils.strip_field_suffix(field) : field
|
140
|
+
fields_key = "#{i18n_base}.fields.#{lookup_field}"
|
113
141
|
field_label = t(fields_key, raise: true)
|
114
142
|
|
115
143
|
base_parts = i18n_base.split(".")
|
@@ -124,34 +152,42 @@ module ChobbleForms
|
|
124
152
|
}
|
125
153
|
end
|
126
154
|
|
127
|
-
sig { params(field_translations: T::Hash[Symbol, T.nilable(String)], value: T.untyped, prefilled: T::Boolean).returns(
|
155
|
+
sig { params(field_translations: T::Hash[Symbol, T.nilable(String)], value: T.untyped, prefilled: T::Boolean).returns(FieldSetupResult) }
|
128
156
|
def build_field_setup_result(field_translations, value, prefilled)
|
129
157
|
form_obj = T.unsafe(instance_variable_get(:@_current_form))
|
130
158
|
i18n_base = T.unsafe(instance_variable_get(:@_current_i18n_base))
|
131
159
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
160
|
+
T.cast(
|
161
|
+
{
|
162
|
+
form_object: form_obj,
|
163
|
+
i18n_base: i18n_base,
|
164
|
+
value:,
|
165
|
+
prefilled:
|
166
|
+
}.merge(field_translations),
|
167
|
+
FieldSetupResult
|
168
|
+
)
|
138
169
|
end
|
139
170
|
|
140
|
-
sig { params(model: T.untyped, field: Symbol).returns(T
|
171
|
+
sig { params(model: T.untyped, field: Symbol).returns({value: T.untyped, prefilled: T::Boolean}) }
|
141
172
|
def resolve_field_value(model, field)
|
142
173
|
field_str = field.to_s
|
143
174
|
|
144
|
-
if field_str.include?("password")
|
145
|
-
return {value: nil, prefilled: false}
|
146
|
-
end
|
147
|
-
|
148
|
-
current_value = model.send(field) if model.respond_to?(field)
|
175
|
+
return {value: nil, prefilled: false} if field_str.include?("password")
|
149
176
|
|
150
|
-
|
151
|
-
|
152
|
-
|
177
|
+
# For composite partials, we receive the base field but need to check for suffixed fields
|
178
|
+
# Check for _pass field first (in case both base and _pass exist)
|
179
|
+
if model.respond_to?("#{field}_pass")
|
180
|
+
current_value = model.send("#{field}_pass")
|
181
|
+
elsif model.respond_to?(field)
|
182
|
+
current_value = model.send(field)
|
183
|
+
else
|
184
|
+
raise "Field '#{field}' or '#{field}_pass' not found on #{model.class.name}. Available fields: #{model.attributes.keys.sort.join(", ")}"
|
153
185
|
end
|
154
186
|
|
187
|
+
# Check if this field should not be prefilled based on excluded fields list
|
188
|
+
excluded_fields = T.unsafe(instance_variable_get(:@_excluded_prefill_fields))
|
189
|
+
return {value: current_value, prefilled: false} if excluded_fields&.include?(field)
|
190
|
+
|
155
191
|
prev_inspection = T.unsafe(instance_variable_get(:@previous_inspection))
|
156
192
|
previous_value = extract_previous_value(prev_inspection, model, field)
|
157
193
|
|
@@ -8,6 +8,7 @@
|
|
8
8
|
# url: Form submission URL (defaults to model's update path)
|
9
9
|
# method: HTTP method (defaults to :patch for models, :post for scoped forms)
|
10
10
|
# local: Use standard form submission instead of Turbo (defaults to false)
|
11
|
+
# excluded_prefill_fields: Array of field symbols that should not be prefilled
|
11
12
|
|
12
13
|
if model
|
13
14
|
url ||= url_for(model)
|
@@ -52,6 +53,11 @@ end %>
|
|
52
53
|
<% @_current_form = form %>
|
53
54
|
<% @_current_i18n_base = i18n_base %>
|
54
55
|
|
56
|
+
<% # Set excluded prefill fields if provided %>
|
57
|
+
<% if local_assigns[:excluded_prefill_fields] %>
|
58
|
+
<% @_excluded_prefill_fields = excluded_prefill_fields %>
|
59
|
+
<% end %>
|
60
|
+
|
55
61
|
<%= yield form %>
|
56
62
|
|
57
63
|
<% if model && model.respond_to?(:errors) && model.errors.any? %>
|
@@ -1,13 +1,14 @@
|
|
1
1
|
<%
|
2
2
|
# Composite partial for pass/fail + comment fields with grid layout
|
3
3
|
# Required parameters:
|
4
|
-
# field: Base field name (e.g., '
|
4
|
+
# field: Base field name (e.g., 'seam_integrity')
|
5
5
|
#
|
6
6
|
# This will render:
|
7
|
-
# - Pass/fail field: field (e.g., 'seam_integrity_pass')
|
7
|
+
# - Pass/fail field: base field + '_pass' (e.g., 'seam_integrity_pass')
|
8
8
|
# - Comment field: base field + '_comment' (e.g., 'seam_integrity_comment')
|
9
9
|
|
10
10
|
base_field = field.to_s.gsub(/_pass$/, "")
|
11
|
+
pass_field = "#{base_field}_pass".to_sym
|
11
12
|
comment_field = "#{base_field}_comment".to_sym
|
12
13
|
|
13
14
|
form = @_current_form
|
@@ -30,7 +31,7 @@
|
|
30
31
|
</label>
|
31
32
|
|
32
33
|
<%= render 'chobble_forms/radio_pass_fail',
|
33
|
-
field:
|
34
|
+
field: pass_field,
|
34
35
|
prefilled: field_data[:prefilled],
|
35
36
|
checked_value: checked_value %>
|
36
37
|
|
@@ -1,15 +1,16 @@
|
|
1
1
|
<%
|
2
2
|
# Composite partial for pass/fail + N/A + comment fields with grid layout
|
3
3
|
# Required parameters:
|
4
|
-
# field: Base field name (e.g., '
|
4
|
+
# field: Base field name (e.g., 'seam_integrity')
|
5
5
|
#
|
6
6
|
# This will render:
|
7
|
-
# - Pass/fail/N/A field: field (e.g., 'seam_integrity_pass')
|
7
|
+
# - Pass/fail/N/A field: base field + '_pass' (e.g., 'seam_integrity_pass')
|
8
8
|
# - Enum fields: Pass = "pass", Fail = "fail", N/A = "na" (rendered as radio buttons)
|
9
9
|
# - Boolean fields: Pass = true, Fail = false (rendered as radio buttons)
|
10
10
|
# - Comment field: base field + '_comment' (e.g., 'seam_integrity_comment')
|
11
11
|
|
12
12
|
base_field = field.to_s.gsub(/_pass$/, "")
|
13
|
+
pass_field = "#{base_field}_pass".to_sym
|
13
14
|
comment_field = "#{base_field}_comment".to_sym
|
14
15
|
|
15
16
|
form = @_current_form
|
@@ -31,7 +32,7 @@
|
|
31
32
|
</label>
|
32
33
|
|
33
34
|
<%= render 'chobble_forms/radio_pass_fail',
|
34
|
-
field:
|
35
|
+
field: pass_field,
|
35
36
|
prefilled: field_data[:prefilled],
|
36
37
|
checked_value: checked_value %>
|
37
38
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chobble-forms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chobble.com
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-08-
|
11
|
+
date: 2025-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|