inline_forms 7.2.11 → 7.9.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/CHANGELOG.md +286 -0
- data/README.rdoc +14 -2
- data/app/assets/javascripts/inline_forms/inline_forms.js +26 -10
- data/app/assets/stylesheets/inline_forms/inline_forms.scss +33 -16
- data/app/controllers/concerns/versions_concern.rb +2 -3
- data/app/controllers/inline_forms_application_controller.rb +5 -1
- data/app/controllers/inline_forms_controller.rb +185 -34
- data/app/helpers/form_elements/ckeditor.rb +4 -30
- data/app/helpers/form_elements/plain_text.rb +23 -0
- data/app/helpers/form_elements/plain_text_area.rb +7 -3
- data/app/helpers/form_elements/text_area.rb +4 -44
- data/app/helpers/form_elements/text_area_without_ckeditor.rb +5 -4
- data/app/helpers/form_elements/text_field.rb +2 -2
- data/app/helpers/inline_forms_helper.rb +144 -74
- data/app/views/devise/sessions/_form.html.erb +4 -1
- data/app/views/inline_forms/_close.html.erb +9 -5
- data/app/views/inline_forms/_edit.html.erb +8 -41
- data/app/views/inline_forms/_list.html.erb +53 -55
- data/app/views/inline_forms/_new.html.erb +22 -12
- data/app/views/inline_forms/_show.html.erb +13 -37
- data/app/views/inline_forms/_versions.html.erb +5 -4
- data/app/views/inline_forms/_versions_list.html.erb +8 -12
- data/app/views/inline_forms/create_list_frame.html.erb +3 -0
- data/app/views/inline_forms/field_edit.html.erb +3 -0
- data/app/views/inline_forms/field_show.html.erb +3 -0
- data/app/views/inline_forms/new_record.html.erb +3 -0
- data/app/views/inline_forms/row_close.html.erb +13 -0
- data/app/views/inline_forms/row_destroyed.html.erb +9 -0
- data/app/views/inline_forms/row_show.html.erb +3 -0
- data/app/views/inline_forms/versions_list_panel.html.erb +3 -0
- data/app/views/inline_forms/versions_panel.html.erb +6 -0
- data/app/views/layouts/application.html.erb +2 -5
- data/app/views/layouts/inline_forms.html.erb +12 -6
- data/archived/README.md +47 -0
- data/archived/form_elements/README.md +27 -0
- data/archived/form_elements/chicas/README.md +31 -0
- data/archived/form_elements/geo_code_curacao/README.md +62 -0
- data/{app → archived/form_elements/geo_code_curacao/app}/helpers/form_elements/geo_code_curacao.rb +0 -1
- data/archived/form_elements/geo_code_curacao/app/views/geo_code_curacao/list_streets.html.erb +1 -0
- data/archived/form_elements/geo_code_curacao/app/views/geo_code_curacao/list_streets.js.erb +1 -0
- data/archived/form_elements/kansen_slider/README.md +31 -0
- data/archived/form_elements/tree/README.md +47 -0
- data/archived/form_elements/tree/app/views/inline_forms/_show_tree.html.erb +30 -0
- data/{app → archived/form_elements/tree/app}/views/inline_forms/_tree.html.erb +18 -5
- data/bin/inline_forms +22 -1
- data/bin/inline_forms_installer_core.rb +108 -8
- data/docs/ujs-to-turbo.md +192 -0
- data/lib/generators/USAGE +2 -2
- data/lib/generators/assets/stylesheets/inline_forms.scss +33 -16
- data/lib/inline_forms/archived_form_elements.rb +70 -0
- data/lib/inline_forms/version.rb +1 -1
- data/lib/inline_forms.rb +60 -2
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_field_turbo_test.rb +73 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_name_list_test.rb +73 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_name_required_test.rb +21 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_photos_pagination_test.rb +227 -15
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_row_turbo_test.rb +103 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_top_level_new_test.rb +70 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_top_level_pagination_test.rb +40 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_versions_turbo_test.rb +120 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_photo_revert_test.rb +94 -0
- data/lib/installer_templates/example_app_tests/test/integration/example_app_turbo_layout_test.rb +6 -9
- data/lib/installer_templates/example_app_tests/test/models/example_app_apartment_name_validation_test.rb +16 -0
- data/lib/installer_templates/example_app_tests/test/models/example_app_plain_text_rich_text_edge_cases_test.rb +46 -0
- data/lib/installer_templates/example_app_views/apartments/name_list.html.erb +26 -0
- data/lib/installer_templates/example_app_views/inline_forms/_header.html.erb +45 -0
- data/test/archived_form_elements_test.rb +41 -0
- data/test/form_element_from_callee_test.rb +2 -2
- data/test/inline_forms_generator_test.rb +10 -0
- data/test/plain_text_configuration_test.rb +90 -0
- metadata +45 -24
- data/app/views/geo_code_curacao/list_streets.html.erb +0 -1
- data/app/views/geo_code_curacao/list_streets.js.erb +0 -1
- data/app/views/inline_forms/close.js.erb +0 -4
- data/app/views/inline_forms/edit.js.erb +0 -1
- data/app/views/inline_forms/list.js.erb +0 -1
- data/app/views/inline_forms/new.js.erb +0 -1
- data/app/views/inline_forms/record_destroyed.js.erb +0 -1
- data/app/views/inline_forms/show.js.erb +0 -1
- data/app/views/inline_forms/show_element.js.erb +0 -1
- data/app/views/inline_forms/show_undo.js.erb +0 -1
- data/app/views/inline_forms/update.js.erb +0 -1
- data/app/views/inline_forms/versions.js.erb +0 -4
- data/app/views/inline_forms/versions_list.js.erb +0 -1
- data/lib/generators/assets/javascripts/ckeditor/config.js +0 -72
- /data/{app → archived/form_elements/chicas/app}/helpers/form_elements/chicas_dropdown_with_family_members.rb +0 -0
- /data/{app → archived/form_elements/chicas/app}/helpers/form_elements/chicas_family_photo_list.rb +0 -0
- /data/{app → archived/form_elements/chicas/app}/helpers/form_elements/chicas_photo_list.rb +0 -0
- /data/{app → archived/form_elements/geo_code_curacao/app}/controllers/geo_code_curacao_controller.rb +0 -0
- /data/{app → archived/form_elements/geo_code_curacao/app}/models/geo_code_curacao.rb +0 -0
- /data/{app → archived/form_elements/kansen_slider/app}/helpers/form_elements/kansen_slider.rb +0 -0
- /data/{app → archived/form_elements/tree/app}/helpers/form_elements/move.rb +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../example_app/example_integration_test_case"
|
|
4
|
+
|
|
5
|
+
class ExampleAppApartmentVersionsTurboTest < ExampleAppIntegrationTestCase
|
|
6
|
+
setup do
|
|
7
|
+
@apartment = Apartment.first || Apartment.create!(name: "Versions Turbo", title: "T")
|
|
8
|
+
@versions_frame = "apartment_#{@apartment.id}_versions"
|
|
9
|
+
@headers = { "Turbo-Frame" => @versions_frame, "Accept" => "text/html" }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
test "versions list opens inside matching turbo-frame" do
|
|
13
|
+
get list_versions_apartment_path(@apartment, update: @versions_frame), headers: @headers
|
|
14
|
+
assert_response :success
|
|
15
|
+
assert_includes @response.body, %(<turbo-frame id="#{@versions_frame}">)
|
|
16
|
+
assert_includes @response.body, "Changeset"
|
|
17
|
+
refute_includes @response.body, 'data-remote="true"'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
test "versions list close returns panel header inside turbo-frame" do
|
|
21
|
+
get list_versions_apartment_path(@apartment, update: @versions_frame, close: true),
|
|
22
|
+
headers: @headers
|
|
23
|
+
assert_response :success
|
|
24
|
+
assert_includes @response.body, %(<turbo-frame id="#{@versions_frame}">)
|
|
25
|
+
refute_includes @response.body, "Changeset"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
test "expanded row versions open link uses Turbo not UJS remote" do
|
|
29
|
+
row_frame = "apartment_#{@apartment.id}"
|
|
30
|
+
get apartment_path(@apartment, update: row_frame),
|
|
31
|
+
headers: { "Turbo-Frame" => row_frame, "Accept" => "text/html" }
|
|
32
|
+
assert_response :success
|
|
33
|
+
assert_select "turbo-frame##{@versions_frame} a[data-turbo='true'][data-turbo-frame='#{@versions_frame}']", minimum: 1
|
|
34
|
+
refute_select "turbo-frame##{@versions_frame} a[data-remote='true']"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
test "restore link in versions list requests turbo-stream (nested versions frame)" do
|
|
38
|
+
apt = Apartment.create!(name: "Stream Link", title: "T")
|
|
39
|
+
apt.update!(title: "T2")
|
|
40
|
+
vf = "apartment_#{apt.id}_versions"
|
|
41
|
+
get list_versions_apartment_path(apt, update: vf),
|
|
42
|
+
headers: { "Turbo-Frame" => vf, "Accept" => "text/html" }
|
|
43
|
+
assert_response :success
|
|
44
|
+
assert_match(/data-turbo-stream="true"/, @response.body,
|
|
45
|
+
"restore from inside …_versions must use turbo-stream to avoid Turbo-Frame mismatch")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
test "revert from versions list closes row via turbo-stream when Turbo-Frame is versions" do
|
|
49
|
+
apt = Apartment.create!(name: "Versions Stream Revert", title: "Before")
|
|
50
|
+
apt.update!(title: "After")
|
|
51
|
+
row_frame = "apartment_#{apt.id}"
|
|
52
|
+
versions_frame = "#{row_frame}_versions"
|
|
53
|
+
version = apt.versions.where(event: "update").order(:id).last
|
|
54
|
+
assert version, "expected an update version to revert"
|
|
55
|
+
|
|
56
|
+
post revert_apartment_path(version.id, update: row_frame),
|
|
57
|
+
headers: {
|
|
58
|
+
"Turbo-Frame" => versions_frame,
|
|
59
|
+
"Accept" => "text/vnd.turbo-stream.html"
|
|
60
|
+
}
|
|
61
|
+
assert_response :success
|
|
62
|
+
assert_includes @response.body, %(action="replace")
|
|
63
|
+
assert_includes @response.body, %(target="#{row_frame}")
|
|
64
|
+
assert_includes @response.body, %(target="#{versions_frame}")
|
|
65
|
+
assert_equal "Before", apt.reload.title
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
test "revert from versions list closes row via Turbo POST on row frame" do
|
|
69
|
+
apt = Apartment.create!(name: "Versions Revert", title: "Before")
|
|
70
|
+
apt.update!(title: "After")
|
|
71
|
+
row_frame = "apartment_#{apt.id}"
|
|
72
|
+
versions_frame = "#{row_frame}_versions"
|
|
73
|
+
# 7.9.0 dropped the `format.html` fallback in `revert`; the restore link
|
|
74
|
+
# always requests a turbo-stream now, even when the click happened on
|
|
75
|
+
# the row frame, so the test mirrors that contract.
|
|
76
|
+
row_headers = {
|
|
77
|
+
"Turbo-Frame" => row_frame,
|
|
78
|
+
"Accept" => "text/vnd.turbo-stream.html"
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
version = apt.versions.where(event: "update").order(:id).last
|
|
82
|
+
assert version, "expected an update version to revert"
|
|
83
|
+
|
|
84
|
+
post revert_apartment_path(version.id, update: row_frame), headers: row_headers
|
|
85
|
+
assert_response :success
|
|
86
|
+
assert_includes @response.body, %(action="replace")
|
|
87
|
+
assert_includes @response.body, %(target="#{row_frame}")
|
|
88
|
+
assert_includes @response.body, %(target="#{versions_frame}")
|
|
89
|
+
assert_equal "Before", apt.reload.title
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
test "revert from versions list restores rich_text body via turbo-stream" do
|
|
93
|
+
apt = Apartment.create!(name: "RichText Revert", title: "T")
|
|
94
|
+
apt.update!(description: "<p>old body</p>")
|
|
95
|
+
apt.update!(description: "<p>new body</p>")
|
|
96
|
+
|
|
97
|
+
rich_text = ActionText::RichText.find_by!(
|
|
98
|
+
record_type: Apartment.name, record_id: apt.id, name: "description"
|
|
99
|
+
)
|
|
100
|
+
rich_text_version = rich_text.versions.where(event: "update").order(:id).last
|
|
101
|
+
assert rich_text_version,
|
|
102
|
+
"expected a PaperTrail update version on ActionText::RichText for the description edit"
|
|
103
|
+
|
|
104
|
+
row_frame = "apartment_#{apt.id}"
|
|
105
|
+
versions_frame = "#{row_frame}_versions"
|
|
106
|
+
post revert_apartment_path(rich_text_version.id, update: row_frame),
|
|
107
|
+
headers: {
|
|
108
|
+
"Turbo-Frame" => versions_frame,
|
|
109
|
+
"Accept" => "text/vnd.turbo-stream.html"
|
|
110
|
+
}
|
|
111
|
+
assert_response :success
|
|
112
|
+
assert_includes @response.body, %(action="replace")
|
|
113
|
+
assert_includes @response.body, %(target="#{row_frame}")
|
|
114
|
+
assert_includes @response.body, %(target="#{versions_frame}")
|
|
115
|
+
|
|
116
|
+
apt.reload
|
|
117
|
+
assert_includes apt.description.body.to_html, "old body",
|
|
118
|
+
"rich_text revert should restore the previous body content"
|
|
119
|
+
end
|
|
120
|
+
end
|
data/lib/installer_templates/example_app_tests/test/integration/example_app_photo_revert_test.rb
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../example_app/example_integration_test_case"
|
|
4
|
+
|
|
5
|
+
# 7.9.0 regression: revert from the versions panel for a Photo whose
|
|
6
|
+
# `image` column changed must put back the previous CarrierWave file
|
|
7
|
+
# bytes, not just the previous filename string. Relies on the
|
|
8
|
+
# `ImageUploader` knobs the installer ships:
|
|
9
|
+
#
|
|
10
|
+
# * `CarrierWave.configure { config.remove_previously_stored_files_after_update = false }`
|
|
11
|
+
# (config/initializers/carrierwave.rb)
|
|
12
|
+
# * `remove!` no-op
|
|
13
|
+
# * unique per-upload filename prefix
|
|
14
|
+
#
|
|
15
|
+
# See https://stackoverflow.com/questions/9423279/papertrail-and-carrierwave
|
|
16
|
+
class ExampleAppPhotoRevertTest < ExampleAppIntegrationTestCase
|
|
17
|
+
# Mirror the setup of ExampleAppApartmentPhotosPaginationTest: re-seed
|
|
18
|
+
# Konferensha photos from db/seed_images/ so the test asserts against
|
|
19
|
+
# real CarrierWave file mounts without depending on dev DB state.
|
|
20
|
+
setup do
|
|
21
|
+
@apartment = Apartment.find_or_create_by!(name: "Konferensha") do |a|
|
|
22
|
+
a.title = "Konferensha sobre Papiamentu"
|
|
23
|
+
end
|
|
24
|
+
seed_dir = Rails.root.join("db", "seed_images")
|
|
25
|
+
if seed_dir.directory?
|
|
26
|
+
Dir.glob(seed_dir.join("*.{jpg,jpeg,png,gif}"), File::FNM_CASEFOLD).sort.each do |abs|
|
|
27
|
+
base = File.basename(abs)
|
|
28
|
+
next if Photo.exists?(name: base, apartment_id: @apartment.id)
|
|
29
|
+
File.open(abs, "rb") do |io|
|
|
30
|
+
Photo.create!(
|
|
31
|
+
name: base,
|
|
32
|
+
caption: "Konferensha foto #{base}",
|
|
33
|
+
apartment: @apartment,
|
|
34
|
+
image: io
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
test "revert restores previous CarrierWave file bytes on disk" do
|
|
42
|
+
photo = @apartment.photos.first!
|
|
43
|
+
original_identifier = photo.image.identifier
|
|
44
|
+
original_path = photo.image.path
|
|
45
|
+
assert File.exist?(original_path), "expected seeded photo file on disk: #{original_path}"
|
|
46
|
+
original_size = File.size(original_path)
|
|
47
|
+
|
|
48
|
+
seed_dir = Rails.root.join("db", "seed_images")
|
|
49
|
+
jpgs = Dir.glob(seed_dir.join("*.{jpg,jpeg}"), File::FNM_CASEFOLD).sort
|
|
50
|
+
replacement = jpgs.find { |abs| File.basename(abs) != photo.name } || jpgs.last
|
|
51
|
+
assert replacement, "need at least one seed jpg different from the photo's current mount"
|
|
52
|
+
refute_equal File.size(replacement), original_size,
|
|
53
|
+
"test needs a replacement file with a different byte length so the assertion is meaningful"
|
|
54
|
+
|
|
55
|
+
frame_id = "apartment_#{@apartment.id}_photo_#{photo.id}_image"
|
|
56
|
+
turbo_headers = { "Turbo-Frame" => frame_id, "Accept" => "text/html" }
|
|
57
|
+
uploaded = Rack::Test::UploadedFile.new(replacement, "image/jpeg")
|
|
58
|
+
put photo_path(
|
|
59
|
+
photo,
|
|
60
|
+
attribute: "image",
|
|
61
|
+
form_element: "image_field",
|
|
62
|
+
update: frame_id
|
|
63
|
+
),
|
|
64
|
+
params: { image: uploaded },
|
|
65
|
+
headers: turbo_headers
|
|
66
|
+
assert_response :success
|
|
67
|
+
photo.reload
|
|
68
|
+
refute_equal original_identifier, photo.image.identifier,
|
|
69
|
+
"update should have changed the image identifier"
|
|
70
|
+
|
|
71
|
+
version = photo.versions.where(event: "update").order(:id).last
|
|
72
|
+
assert version, "expected a Photo update version after the image PUT"
|
|
73
|
+
|
|
74
|
+
row_frame = "apartment_#{@apartment.id}_photo_#{photo.id}"
|
|
75
|
+
versions_frame = "apartment_#{@apartment.id}_photo_#{photo.id}_versions"
|
|
76
|
+
post revert_photo_path(version.id, update: row_frame),
|
|
77
|
+
headers: {
|
|
78
|
+
"Turbo-Frame" => versions_frame,
|
|
79
|
+
"Accept" => "text/vnd.turbo-stream.html"
|
|
80
|
+
}
|
|
81
|
+
assert_response :success
|
|
82
|
+
assert_includes @response.body, %(action="replace")
|
|
83
|
+
assert_includes @response.body, %(target="#{row_frame}")
|
|
84
|
+
assert_includes @response.body, %(target="#{versions_frame}")
|
|
85
|
+
|
|
86
|
+
photo.reload
|
|
87
|
+
assert_equal original_identifier, photo.image.identifier,
|
|
88
|
+
"revert should restore the previous CarrierWave identifier"
|
|
89
|
+
assert File.exist?(photo.image.path),
|
|
90
|
+
"revert should leave the previous file bytes on disk (carrierwave config)"
|
|
91
|
+
assert_equal original_size, File.size(photo.image.path),
|
|
92
|
+
"previous file bytes must be byte-identical to the original"
|
|
93
|
+
end
|
|
94
|
+
end
|
data/lib/installer_templates/example_app_tests/test/integration/example_app_turbo_layout_test.rb
CHANGED
|
@@ -2,14 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "../example_app/example_integration_test_case"
|
|
4
4
|
|
|
5
|
-
# Smoke test
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
# fails, frame/stream conversions in later slices will silently fall
|
|
9
|
-
# back to full-page navigation (Turbo not loaded) instead of using the
|
|
10
|
-
# `<turbo-frame>` fast path.
|
|
5
|
+
# Smoke test: layouts load Turbo as an ES module (no Sprockets ESM parse error).
|
|
6
|
+
# Step 5 (7.8.0) leaves Turbo Drive at its default (enabled); inline flows use
|
|
7
|
+
# `<turbo-frame>` + HTML, not jquery-ujs.
|
|
11
8
|
class ExampleAppTurboLayoutTest < ExampleAppIntegrationTestCase
|
|
12
|
-
test "inline_forms layout loads turbo.min.js as an ES module
|
|
9
|
+
test "inline_forms layout loads turbo.min.js as an ES module" do
|
|
13
10
|
get apartments_path
|
|
14
11
|
assert_response :success
|
|
15
12
|
|
|
@@ -19,10 +16,10 @@ class ExampleAppTurboLayoutTest < ExampleAppIntegrationTestCase
|
|
|
19
16
|
"expected the inline_forms layout to import turbo.min.js as a module"
|
|
20
17
|
)
|
|
21
18
|
|
|
22
|
-
|
|
19
|
+
refute_match(
|
|
23
20
|
/Turbo\.session\.drive\s*=\s*false/,
|
|
24
21
|
@response.body,
|
|
25
|
-
"
|
|
22
|
+
"Step 5 enables Turbo Drive by default; disabling it would regress full-page Turbo"
|
|
26
23
|
)
|
|
27
24
|
end
|
|
28
25
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class ExampleAppApartmentNameValidationTest < ActiveSupport::TestCase
|
|
6
|
+
test "apartment requires name" do
|
|
7
|
+
apartment = Apartment.new(title: "No name")
|
|
8
|
+
assert_not apartment.valid?
|
|
9
|
+
assert_includes apartment.errors[:name], "can't be blank"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
test "apartment is valid with name" do
|
|
13
|
+
apartment = Apartment.new(name: "North", title: "Tower")
|
|
14
|
+
assert apartment.valid?
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class ExampleAppPlainTextRichTextEdgeCasesTest < ActiveSupport::TestCase
|
|
6
|
+
def with_temporary_inline_forms_attribute_list(klass, temporary_list)
|
|
7
|
+
original = klass.instance_method(:inline_forms_attribute_list)
|
|
8
|
+
klass.define_method(:inline_forms_attribute_list) { temporary_list }
|
|
9
|
+
yield
|
|
10
|
+
ensure
|
|
11
|
+
klass.define_method(:inline_forms_attribute_list, original)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
test "plain_text mapped to actiontext-backed attribute raises configuration error" do
|
|
15
|
+
with_temporary_inline_forms_attribute_list(
|
|
16
|
+
Apartment,
|
|
17
|
+
[[:description, "description", :plain_text]]
|
|
18
|
+
) do
|
|
19
|
+
error = assert_raises(InlineForms::PlainTextColumnMissingError) do
|
|
20
|
+
InlineForms.validate_plain_text_configuration_for!(Apartment)
|
|
21
|
+
end
|
|
22
|
+
assert_includes(error.message, "description")
|
|
23
|
+
assert_includes(error.message, ":rich_text")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
test "plain_text runtime guard raises before assigning unknown DB attribute" do
|
|
28
|
+
apartment = Apartment.create!(name: "Mismatch", title: "Check")
|
|
29
|
+
assert_raises(InlineForms::PlainTextColumnMissingError) do
|
|
30
|
+
InlineForms.assert_plain_text_column!(
|
|
31
|
+
object: apartment,
|
|
32
|
+
attribute: :description,
|
|
33
|
+
form_element: :plain_text
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
test "switching text column field from plain_text to rich_text does not raise" do
|
|
39
|
+
with_temporary_inline_forms_attribute_list(
|
|
40
|
+
Role,
|
|
41
|
+
[[:description, "description", :rich_text]]
|
|
42
|
+
) do
|
|
43
|
+
InlineForms.validate_plain_text_configuration_for!(Role)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<% @inline_forms_turbo_field = true %>
|
|
2
|
+
<div class="row">
|
|
3
|
+
<div class="small-12 columns">
|
|
4
|
+
<h2>Apartment names (first 10)</h2>
|
|
5
|
+
<p>
|
|
6
|
+
<%= link_to "Back to full apartment list", apartments_path %>
|
|
7
|
+
</p>
|
|
8
|
+
<p class="help-text">
|
|
9
|
+
Each name is an inline edit via <code>text_field_show</code> — no stock
|
|
10
|
+
<code>_show</code> panel. Click a name to edit it in place.
|
|
11
|
+
</p>
|
|
12
|
+
</div>
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<% @apartments.each do |apartment| %>
|
|
16
|
+
<div class="row">
|
|
17
|
+
<div class="small-2 columns">
|
|
18
|
+
<%= apartment.id %>
|
|
19
|
+
</div>
|
|
20
|
+
<div class="small-10 columns">
|
|
21
|
+
<turbo-frame id="apartment_<%= apartment.id %>_name">
|
|
22
|
+
<%= text_field_show(apartment, :name) %>
|
|
23
|
+
</turbo-frame>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<% end %>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
<div class="contain-to-grid fixed">
|
|
2
|
+
<nav id='inline_forms_application_top_bar' class="top-bar">
|
|
3
|
+
<div class="top-bar-left">
|
|
4
|
+
<ul class="menu">
|
|
5
|
+
<li class="menu-text">
|
|
6
|
+
<h1 style="margin: 0; font-size: inherit;"><a href="/"><%= application_name %> v<%= inline_forms_version %> <%= current_user.name %></a></h1>
|
|
7
|
+
</li>
|
|
8
|
+
</ul>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="top-bar-right">
|
|
11
|
+
<ul class="dropdown menu" data-dropdown-menu>
|
|
12
|
+
<% if current_user.role?(:admin) || current_user.role?(:superadmin) %>
|
|
13
|
+
<li>
|
|
14
|
+
<a href="#"><%= t 'common.more' %></a>
|
|
15
|
+
<ul class="menu">
|
|
16
|
+
<% MODEL_TABS.each do |m| %>
|
|
17
|
+
<% model = m.singularize.camelcase.constantize rescue nil %>
|
|
18
|
+
<% unless model.nil? || model.not_accessible_through_html? %>
|
|
19
|
+
<% if can? :update, model %>
|
|
20
|
+
<li>
|
|
21
|
+
<%= link_to model.model_name.human, '/' + m %>
|
|
22
|
+
</li>
|
|
23
|
+
<% end %>
|
|
24
|
+
<% end %>
|
|
25
|
+
<% end %>
|
|
26
|
+
<% if can? :read, Apartment %>
|
|
27
|
+
<li>
|
|
28
|
+
<%= link_to "Apartment names (first 10)", apartment_name_list_path %>
|
|
29
|
+
</li>
|
|
30
|
+
<% end %>
|
|
31
|
+
</ul>
|
|
32
|
+
</li>
|
|
33
|
+
<% end %>
|
|
34
|
+
<li>
|
|
35
|
+
<a href="#"><%= current_user.name %></a>
|
|
36
|
+
<ul class="menu">
|
|
37
|
+
<li>
|
|
38
|
+
<%= link_to( t("common.logout"), destroy_user_session_path, :method => :delete) if current_user %>
|
|
39
|
+
</li>
|
|
40
|
+
</ul>
|
|
41
|
+
</li>
|
|
42
|
+
</ul>
|
|
43
|
+
</div>
|
|
44
|
+
</nav>
|
|
45
|
+
</div>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "test_helper"
|
|
4
|
+
require "inline_forms/archived_form_elements"
|
|
5
|
+
|
|
6
|
+
class ArchivedFormElementsTest < Minitest::Test
|
|
7
|
+
class ModelWithArchivedElement
|
|
8
|
+
def inline_forms_attribute_list
|
|
9
|
+
[[:address, "Address", :geo_code_curacao]]
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class ModelWithArchivedTree
|
|
14
|
+
def inline_forms_attribute_list
|
|
15
|
+
[[:children, "Children", :tree]]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_raises_when_model_declares_archived_geo_code_curacao
|
|
20
|
+
err = assert_raises(InlineForms::ArchivedFormElementError) do
|
|
21
|
+
InlineForms.validate_no_archived_form_elements_for!(ModelWithArchivedElement)
|
|
22
|
+
end
|
|
23
|
+
assert_includes err.message, "geo_code_curacao"
|
|
24
|
+
assert_includes err.message, "7.6.0"
|
|
25
|
+
assert_includes err.message, "archived/form_elements/geo_code_curacao"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_raises_when_model_declares_archived_tree
|
|
29
|
+
err = assert_raises(InlineForms::ArchivedFormElementError) do
|
|
30
|
+
InlineForms.validate_no_archived_form_elements_for!(ModelWithArchivedTree)
|
|
31
|
+
end
|
|
32
|
+
assert_includes err.message, "tree"
|
|
33
|
+
assert_includes err.message, "archived/form_elements/tree"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_archived_registry_documents_absence_list_without_path
|
|
37
|
+
meta = InlineForms::ARCHIVED_FORM_ELEMENTS[:absence_list]
|
|
38
|
+
assert_equal "6.3.0", meta[:removed_in_version]
|
|
39
|
+
assert_nil meta[:archive_path]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -45,9 +45,9 @@ class FormElementFromCalleeTest < Minitest::Test
|
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def test_multi_word_element_name_underscores_preserved
|
|
48
|
-
got = InlineForms.form_element_string_from_callee(:
|
|
48
|
+
got = InlineForms.form_element_string_from_callee(:text_area_without_ckeditor_show)
|
|
49
49
|
assert_equal(
|
|
50
|
-
"
|
|
50
|
+
"text_area_without_ckeditor",
|
|
51
51
|
got,
|
|
52
52
|
"Form element names with underscores must survive unchanged except for _show."
|
|
53
53
|
)
|
|
@@ -100,6 +100,16 @@ class InlineFormsGeneratorTest < Minitest::Test
|
|
|
100
100
|
refute_includes(migration, "t.text :content")
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
def test_plain_text_generates_text_column_and_plain_text_form_element
|
|
104
|
+
run_generator("Note", "title:string", "description:plain_text")
|
|
105
|
+
|
|
106
|
+
model = read("app/models/note.rb")
|
|
107
|
+
migration = read_single_migration_for("notes")
|
|
108
|
+
|
|
109
|
+
assert_includes(model, "[ :description , \"description\", :plain_text ]")
|
|
110
|
+
assert_includes(migration, "t.text :description")
|
|
111
|
+
end
|
|
112
|
+
|
|
103
113
|
private
|
|
104
114
|
|
|
105
115
|
def build_destination_skeleton!
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "test_helper"
|
|
4
|
+
require "rails"
|
|
5
|
+
require "inline_forms"
|
|
6
|
+
|
|
7
|
+
class PlainTextConfigurationTest < Minitest::Test
|
|
8
|
+
class PlainTextModelWithColumn
|
|
9
|
+
def self.table_exists?
|
|
10
|
+
true
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.column_names
|
|
14
|
+
%w[id description]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.table_name
|
|
18
|
+
"plain_text_model_with_columns"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def inline_forms_attribute_list
|
|
22
|
+
[
|
|
23
|
+
[:description, "description", :plain_text]
|
|
24
|
+
]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class PlainTextModelWithoutColumn
|
|
29
|
+
def self.table_exists?
|
|
30
|
+
true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.column_names
|
|
34
|
+
%w[id]
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.table_name
|
|
38
|
+
"plain_text_model_without_columns"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def inline_forms_attribute_list
|
|
42
|
+
[
|
|
43
|
+
[:description, "description", :plain_text]
|
|
44
|
+
]
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class RichTextModelWithoutColumn
|
|
49
|
+
def self.table_exists?
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.column_names
|
|
54
|
+
%w[id]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def inline_forms_attribute_list
|
|
58
|
+
[
|
|
59
|
+
[:description, "description", :rich_text]
|
|
60
|
+
]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_plain_text_column_check_passes_when_column_exists
|
|
65
|
+
model = PlainTextModelWithColumn.new
|
|
66
|
+
InlineForms.assert_plain_text_column!(object: model, attribute: :description, form_element: :plain_text)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_plain_text_column_check_raises_when_column_missing
|
|
70
|
+
model = PlainTextModelWithoutColumn.new
|
|
71
|
+
error = assert_raises(InlineForms::PlainTextColumnMissingError) do
|
|
72
|
+
InlineForms.assert_plain_text_column!(object: model, attribute: :description, form_element: :plain_text)
|
|
73
|
+
end
|
|
74
|
+
assert_includes(error.message, "has no DB column")
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_configuration_check_raises_for_plain_text_without_column
|
|
78
|
+
assert_raises(InlineForms::PlainTextColumnMissingError) do
|
|
79
|
+
InlineForms.validate_plain_text_configuration_for!(PlainTextModelWithoutColumn)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def test_configuration_check_allows_rich_text_without_column
|
|
84
|
+
InlineForms.validate_plain_text_configuration_for!(RichTextModelWithoutColumn)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def test_text_area_alias_is_not_treated_as_plain_text_column_requirement
|
|
88
|
+
refute InlineForms.plain_text_form_element?(:text_area)
|
|
89
|
+
end
|
|
90
|
+
end
|