inline_forms 8.1.59 → 8.1.61
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/CHANGELOG.md +36 -0
- data/lib/generators/templates/application_record.rb +2 -1
- data/lib/inline_forms/dropdown_order.rb +10 -4
- data/lib/inline_forms/form_elements/check_list_helper.rb +3 -0
- data/lib/inline_forms/form_elements/dropdown_helper.rb +2 -1
- data/lib/inline_forms/form_elements/pdf_link_helper.rb +2 -1
- data/lib/inline_forms/version.rb +1 -1
- data/test/integration/dropdown_test.rb +42 -0
- data/test/integration/legacy_elements_test.rb +18 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1c2157f464ca5f6e0a7f42dfbf783dfdbcd606942f8c40be8385479237889794
|
|
4
|
+
data.tar.gz: aa502e01d242a09fc6989b5f7f865c9fbbde33a98592273116daf07d96a8821d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9ca4f57a7ae8c58b68b63103553b6de3f59f187b9fa9cef64fdaa9e5dcdfb494a69dfbce24f3207b0c6198c08dd03d79de84d6c542283115959edd3b7518e776
|
|
7
|
+
data.tar.gz: 651bf78a377bebbdb9fbf1a17f6ad995e00c5de0b399c90377f2680db8d816d592ebf394a8d49a963a244798a890e04c9a09554486767e7c59487e2cbe3da69c
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,42 @@ All notable changes to this project are documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [8.1.61] - 2026-10-30
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **`pdf_link`: the `preview` and `pdf` links work again under Turbo.** They sit inside the field's `<turbo-frame>`, so a click loaded the response into that frame: the preview showed Turbo's "Content missing", and the PDF, which is not HTML, went to the same frame. Both links now carry `data-turbo="false"`, as `simple_file_field`'s download link does, and the preview opens in a new tab so the record stays open. An app that worked around this can drop its override.
|
|
12
|
+
|
|
13
|
+
### Tests
|
|
14
|
+
|
|
15
|
+
- `legacy_elements_test`: both `pdf_link` links carry `data-turbo="false"`, and only the preview has `target="_blank"`.
|
|
16
|
+
|
|
17
|
+
### Lockstep
|
|
18
|
+
|
|
19
|
+
- validation_hints 8.1.61, inline_forms_installer 8.1.61, inline_forms_schema_edit 8.1.61.
|
|
20
|
+
|
|
21
|
+
## [8.1.60] - 2026-10-28
|
|
22
|
+
|
|
23
|
+
Fixes from a review of 8.1.58 and 8.1.59.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **Dropdowns take only the order from `inline_forms_list`.** 8.1.59's rule 3 merged the whole `inline_forms_list` scope into `dropdown` and `dropdown_with_other`, so a `where` or `joins` there hid records from the dropdown. A record whose current value was hidden showed the first option instead, and saving the inline form silently changed it. Rule 3 now uses only the scope's ORDER BY (added to a `default_scope` order, as the merge did). The scope still filters `/index`.
|
|
28
|
+
- **`check_list` keeps the `inline_forms_list` filter.** Under rules 1 and 2 (a declared order or a `dropdown_order` column) 8.1.59 skipped the scope, so `check_list` listed records its `where` used to hide. It now applies the scope's filter under every rule, as before 8.1.59; the order is still `InlineForms::DropdownOrder`'s.
|
|
29
|
+
- **A `dropdown` whose lookup defines `disabled_for_dropdown?` loads the lookup once.** 8.1.59 loaded it to find the disabled options and again, ordered, for the options.
|
|
30
|
+
- **Installer: a gem path with a space no longer breaks the Dart Sass build.** 8.1.58's initializer put the gem's stylesheet dir first as a `build_options` entry, and dartsass-rails splits those on whitespace, so a gem installed under e.g. `/Users/John Doe/…` gave Sass two broken arguments. `config/initializers/inline_forms_dartsass_builds.rb` now prepends the dir to `Dartsass::Runner`'s own `--load-path` list as a separate argument, still ahead of `app/assets/builds`. Apps generated with 8.1.58 or 8.1.59 can copy the new initializer from the installer's `lib/installer_templates/dartsass/`.
|
|
31
|
+
- **Example app: rolling back the seed migration works.** Its `down` destroyed the seeded owners while the seeded apartments still pointed at them, and `apartments.owner_id` / `apartments.phase_id` have foreign keys, so `Owner#destroy` raised `ActiveRecord::InvalidForeignKey`. It now sets those columns to NULL on every apartment that points at a seeded owner or phase before destroying it.
|
|
32
|
+
- The installer's `ApplicationRecord` template says rule 3 is the ORDER BY of `inline_forms_list`.
|
|
33
|
+
|
|
34
|
+
### Tests
|
|
35
|
+
|
|
36
|
+
- `dropdown_test`: a filtering `inline_forms_list` orders a dropdown without hiding records, `check_list` keeps that filter under a declared order, and `disabled_for_dropdown?` costs no second query.
|
|
37
|
+
- Example app: `example_app_dartsass_build_test` checks that the gem's stylesheet dir is the first `--load-path` and a separate argument.
|
|
38
|
+
|
|
39
|
+
### Lockstep
|
|
40
|
+
|
|
41
|
+
- validation_hints 8.1.60, inline_forms_installer 8.1.60, inline_forms_schema_edit 8.1.60.
|
|
42
|
+
|
|
7
43
|
## [8.1.59] - 2026-10-22
|
|
8
44
|
|
|
9
45
|
### Fixed
|
|
@@ -31,7 +31,8 @@ class ApplicationRecord < ActiveRecord::Base
|
|
|
31
31
|
# 1. inline_forms_dropdown_order :col # or :col, :desc
|
|
32
32
|
# 2. a `dropdown_order` integer column, ascending (e.g. '---' 0,
|
|
33
33
|
# 'helprequest' 10, 'decision' 20, 'admittance' 30)
|
|
34
|
-
# 3. inline_forms_list above
|
|
34
|
+
# 3. the order of inline_forms_list above (only its ORDER BY: a where
|
|
35
|
+
# there filters #index, not the dropdowns)
|
|
35
36
|
# 4. database order
|
|
36
37
|
# 1 and 2 put NULLs last and break ties on id.
|
|
37
38
|
|
|
@@ -7,11 +7,13 @@ module InlineForms
|
|
|
7
7
|
# 1. the model declares `inline_forms_dropdown_order :column, :asc|:desc`;
|
|
8
8
|
# 2. the table has a `dropdown_order` column (ascending), so a lookup can
|
|
9
9
|
# put '---' / 'onbekend' first and process phases in process order;
|
|
10
|
-
# 3. the model's `inline_forms_list` scope (its list order
|
|
10
|
+
# 3. the ORDER BY of the model's `inline_forms_list` scope (its list order;
|
|
11
|
+
# only the order: a where/joins in that scope does not hide records here);
|
|
11
12
|
# 4. database order (a default_scope order included).
|
|
12
13
|
#
|
|
13
14
|
# 1 and 2 replace any default_scope order, put NULLs last (a record nobody
|
|
14
|
-
# numbered yet goes to the end) and break ties on the primary key.
|
|
15
|
+
# numbered yet goes to the end) and break ties on the primary key. 3 adds to
|
|
16
|
+
# a default_scope order, as merging the scope did.
|
|
15
17
|
#
|
|
16
18
|
# The macro is on every Active Record model (engine initializer), so hosts
|
|
17
19
|
# need no ApplicationRecord change.
|
|
@@ -51,11 +53,15 @@ module InlineForms
|
|
|
51
53
|
keys = [ table[column].public_send(direction).nulls_last ]
|
|
52
54
|
keys << table[klass.primary_key].asc if klass.primary_key && klass.primary_key != column
|
|
53
55
|
relation.reorder(*keys)
|
|
54
|
-
elsif klass.
|
|
55
|
-
relation.
|
|
56
|
+
elsif (list_order = list_order_values(klass)).any?
|
|
57
|
+
relation.order(*list_order)
|
|
56
58
|
else
|
|
57
59
|
relation
|
|
58
60
|
end
|
|
59
61
|
end
|
|
62
|
+
|
|
63
|
+
def self.list_order_values(klass)
|
|
64
|
+
klass.respond_to?(:inline_forms_list) ? klass.inline_forms_list.order_values : []
|
|
65
|
+
end
|
|
60
66
|
end
|
|
61
67
|
end
|
|
@@ -21,6 +21,9 @@ module InlineForms
|
|
|
21
21
|
object.send(attribute).build if object.send(attribute).empty?
|
|
22
22
|
klass = object.send(attribute).first.class
|
|
23
23
|
values = cancan_enabled? ? klass.accessible_by(current_ability) : klass.all
|
|
24
|
+
# check_list has always applied the list scope's filter (a where in
|
|
25
|
+
# inline_forms_list hides records here); the order is DropdownOrder's.
|
|
26
|
+
values = values.merge(klass.inline_forms_list.unscope(:order)) if klass.respond_to?(:inline_forms_list)
|
|
24
27
|
values = InlineForms::DropdownOrder.apply(values)
|
|
25
28
|
out = ''
|
|
26
29
|
values.each do | item |
|
|
@@ -25,11 +25,12 @@ module InlineForms
|
|
|
25
25
|
else
|
|
26
26
|
values = klass.all
|
|
27
27
|
end
|
|
28
|
+
values = InlineForms::DropdownOrder.apply(values)
|
|
28
29
|
options_disabled = nil
|
|
29
30
|
if klass.method_defined? :disabled_for_dropdown?
|
|
31
|
+
# loads values; collection_select below reuses the loaded records
|
|
30
32
|
options_disabled = values.map{|v| v.id if v.disabled_for_dropdown?}.compact
|
|
31
33
|
end
|
|
32
|
-
values = InlineForms::DropdownOrder.apply(values)
|
|
33
34
|
# the leading underscore is to avoid name conflicts, like 'email' and 'email_type' will result in 'email' and 'email[email_type_id]' in the form!
|
|
34
35
|
collection_select( ('_' + object.class.to_s.underscore).to_sym,
|
|
35
36
|
attribute.to_s.foreign_key.to_sym,
|
|
@@ -7,7 +7,8 @@ module InlineForms
|
|
|
7
7
|
|
|
8
8
|
def pdf_link_show(object, attribute)
|
|
9
9
|
# the attribute is the action
|
|
10
|
-
|
|
10
|
+
# turbo:false so the links leave the field's turbo-frame: the preview has no matching frame ("Content missing") and the PDF is not HTML; the preview gets its own tab so the record stays open
|
|
11
|
+
"#{link_to 'preview', "/#{attribute}/#{object.id}", :class => "pdf_preview", :target => "_blank", :data => { :turbo => false }} #{link_to 'pdf', "/#{attribute}/#{object.id}.pdf", :class => "pdf_open", :data => { :turbo => false }}".html_safe
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def pdf_link_edit(object, attribute)
|
data/lib/inline_forms/version.rb
CHANGED
|
@@ -10,6 +10,11 @@ class DropdownTest < InlineFormsIntegrationTestCase
|
|
|
10
10
|
[ Phase, Machine, Kind, Part ].each do |klass|
|
|
11
11
|
klass.remove_instance_variable(:@inline_forms_dropdown_order) if klass.instance_variable_defined?(:@inline_forms_dropdown_order)
|
|
12
12
|
end
|
|
13
|
+
# Back to ApplicationRecord's `inline_forms_list -> { all }`.
|
|
14
|
+
[ Kind, Part ].each do |klass|
|
|
15
|
+
klass.singleton_class.remove_method(:inline_forms_list) if klass.singleton_class.method_defined?(:inline_forms_list, false)
|
|
16
|
+
end
|
|
17
|
+
Phase.remove_method(:disabled_for_dropdown?) if Phase.method_defined?(:disabled_for_dropdown?, false)
|
|
13
18
|
end
|
|
14
19
|
|
|
15
20
|
def view
|
|
@@ -76,6 +81,32 @@ class DropdownTest < InlineFormsIntegrationTestCase
|
|
|
76
81
|
assert_equal %w[Zeta Alpha], InlineForms::DropdownOrder.apply(Kind.all).map(&:name)
|
|
77
82
|
end
|
|
78
83
|
|
|
84
|
+
test "a filtering inline_forms_list only orders a dropdown, it hides no records" do
|
|
85
|
+
%w[Zeta Hidden Alpha].each { |name| Kind.create!(name: name) }
|
|
86
|
+
Kind.define_singleton_method(:inline_forms_list) { where.not(name: "Hidden").order(:name, :id) }
|
|
87
|
+
|
|
88
|
+
html = view.dropdown_with_other_edit(Widget.create!(name: "W"), :kind)
|
|
89
|
+
|
|
90
|
+
assert_equal %w[Alpha Hidden Zeta], html.scan(/<option value="([^"]*)">/).flatten
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
test "disabled_for_dropdown? and the options come from one query" do
|
|
94
|
+
create_phases
|
|
95
|
+
Phase.define_method(:disabled_for_dropdown?) { name == "decision" }
|
|
96
|
+
selects = []
|
|
97
|
+
counter = ->(*, payload) { selects << payload[:sql] if payload[:sql].match?(/\ASELECT .*FROM "phases"/) }
|
|
98
|
+
|
|
99
|
+
view_context, part = view, Part.create!(name: "Gear")
|
|
100
|
+
|
|
101
|
+
html = ActiveSupport::Notifications.subscribed(counter, "sql.active_record") do
|
|
102
|
+
view_context.dropdown_edit(part, :phase)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
assert_equal 1, selects.size, selects.join("\n")
|
|
106
|
+
assert_match(/<option disabled="disabled" value="\d+">decision</, html)
|
|
107
|
+
assert_equal [ "---", "helprequest", "decision", "admittance", "nieuw" ], option_texts(html)
|
|
108
|
+
end
|
|
109
|
+
|
|
79
110
|
test "dropdown_with_other offers its datalist in the dropdown order" do
|
|
80
111
|
%w[Zeta Alpha Mu].each { |name| Kind.create!(name: name) }
|
|
81
112
|
Kind.inline_forms_dropdown_order :name
|
|
@@ -95,6 +126,17 @@ class DropdownTest < InlineFormsIntegrationTestCase
|
|
|
95
126
|
assert_equal %w[Nut Bolt Axle], html.scan(%r{<label for=[^>]*>([^<]*)</label>}).flatten.reject(&:empty?)
|
|
96
127
|
end
|
|
97
128
|
|
|
129
|
+
test "check_list keeps the inline_forms_list filter under a declared order" do
|
|
130
|
+
machine = Machine.create!(name: "Press")
|
|
131
|
+
%w[Bolt Hidden Nut Axle].each { |name| Part.create!(name: name) }
|
|
132
|
+
Part.define_singleton_method(:inline_forms_list) { where.not(name: "Hidden").order(:name) }
|
|
133
|
+
Part.inline_forms_dropdown_order :name, :desc
|
|
134
|
+
|
|
135
|
+
html = view.check_list_edit(machine, :parts)
|
|
136
|
+
|
|
137
|
+
assert_equal %w[Nut Bolt Axle], html.scan(%r{<label for=[^>]*>([^<]*)</label>}).flatten.reject(&:empty?)
|
|
138
|
+
end
|
|
139
|
+
|
|
98
140
|
test "an unknown direction or column is refused" do
|
|
99
141
|
assert_raises(ArgumentError) { Phase.inline_forms_dropdown_order :name, :up }
|
|
100
142
|
|
|
@@ -51,4 +51,22 @@ class LegacyElementsTest < InlineFormsIntegrationTestCase
|
|
|
51
51
|
assert_includes response.body, %(href="/report/#{@widget.id}")
|
|
52
52
|
assert_includes response.body, %(href="/report/#{@widget.id}.pdf")
|
|
53
53
|
end
|
|
54
|
+
|
|
55
|
+
test "pdf_link links leave the field's turbo frame" do
|
|
56
|
+
frame = "widget_#{@widget.id}"
|
|
57
|
+
get widget_path(@widget, update: frame), headers: frame_headers(frame)
|
|
58
|
+
|
|
59
|
+
assert_response :success
|
|
60
|
+
assert_select %(a[href="/report/#{@widget.id}"][data-turbo="false"])
|
|
61
|
+
assert_select %(a[href="/report/#{@widget.id}.pdf"][data-turbo="false"])
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
test "pdf_link preview opens in a new tab, the pdf link does not" do
|
|
65
|
+
frame = "widget_#{@widget.id}"
|
|
66
|
+
get widget_path(@widget, update: frame), headers: frame_headers(frame)
|
|
67
|
+
|
|
68
|
+
assert_response :success
|
|
69
|
+
assert_select %(a[href="/report/#{@widget.id}"][target="_blank"])
|
|
70
|
+
assert_select %(a[href="/report/#{@widget.id}.pdf"][target]), false
|
|
71
|
+
end
|
|
54
72
|
end
|