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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +286 -0
  3. data/README.rdoc +14 -2
  4. data/app/assets/javascripts/inline_forms/inline_forms.js +26 -10
  5. data/app/assets/stylesheets/inline_forms/inline_forms.scss +33 -16
  6. data/app/controllers/concerns/versions_concern.rb +2 -3
  7. data/app/controllers/inline_forms_application_controller.rb +5 -1
  8. data/app/controllers/inline_forms_controller.rb +185 -34
  9. data/app/helpers/form_elements/ckeditor.rb +4 -30
  10. data/app/helpers/form_elements/plain_text.rb +23 -0
  11. data/app/helpers/form_elements/plain_text_area.rb +7 -3
  12. data/app/helpers/form_elements/text_area.rb +4 -44
  13. data/app/helpers/form_elements/text_area_without_ckeditor.rb +5 -4
  14. data/app/helpers/form_elements/text_field.rb +2 -2
  15. data/app/helpers/inline_forms_helper.rb +144 -74
  16. data/app/views/devise/sessions/_form.html.erb +4 -1
  17. data/app/views/inline_forms/_close.html.erb +9 -5
  18. data/app/views/inline_forms/_edit.html.erb +8 -41
  19. data/app/views/inline_forms/_list.html.erb +53 -55
  20. data/app/views/inline_forms/_new.html.erb +22 -12
  21. data/app/views/inline_forms/_show.html.erb +13 -37
  22. data/app/views/inline_forms/_versions.html.erb +5 -4
  23. data/app/views/inline_forms/_versions_list.html.erb +8 -12
  24. data/app/views/inline_forms/create_list_frame.html.erb +3 -0
  25. data/app/views/inline_forms/field_edit.html.erb +3 -0
  26. data/app/views/inline_forms/field_show.html.erb +3 -0
  27. data/app/views/inline_forms/new_record.html.erb +3 -0
  28. data/app/views/inline_forms/row_close.html.erb +13 -0
  29. data/app/views/inline_forms/row_destroyed.html.erb +9 -0
  30. data/app/views/inline_forms/row_show.html.erb +3 -0
  31. data/app/views/inline_forms/versions_list_panel.html.erb +3 -0
  32. data/app/views/inline_forms/versions_panel.html.erb +6 -0
  33. data/app/views/layouts/application.html.erb +2 -5
  34. data/app/views/layouts/inline_forms.html.erb +12 -6
  35. data/archived/README.md +47 -0
  36. data/archived/form_elements/README.md +27 -0
  37. data/archived/form_elements/chicas/README.md +31 -0
  38. data/archived/form_elements/geo_code_curacao/README.md +62 -0
  39. data/{app → archived/form_elements/geo_code_curacao/app}/helpers/form_elements/geo_code_curacao.rb +0 -1
  40. data/archived/form_elements/geo_code_curacao/app/views/geo_code_curacao/list_streets.html.erb +1 -0
  41. data/archived/form_elements/geo_code_curacao/app/views/geo_code_curacao/list_streets.js.erb +1 -0
  42. data/archived/form_elements/kansen_slider/README.md +31 -0
  43. data/archived/form_elements/tree/README.md +47 -0
  44. data/archived/form_elements/tree/app/views/inline_forms/_show_tree.html.erb +30 -0
  45. data/{app → archived/form_elements/tree/app}/views/inline_forms/_tree.html.erb +18 -5
  46. data/bin/inline_forms +22 -1
  47. data/bin/inline_forms_installer_core.rb +108 -8
  48. data/docs/ujs-to-turbo.md +192 -0
  49. data/lib/generators/USAGE +2 -2
  50. data/lib/generators/assets/stylesheets/inline_forms.scss +33 -16
  51. data/lib/inline_forms/archived_form_elements.rb +70 -0
  52. data/lib/inline_forms/version.rb +1 -1
  53. data/lib/inline_forms.rb +60 -2
  54. data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_field_turbo_test.rb +73 -0
  55. data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_name_list_test.rb +73 -0
  56. data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_name_required_test.rb +21 -0
  57. data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_photos_pagination_test.rb +227 -15
  58. data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_row_turbo_test.rb +103 -0
  59. data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_top_level_new_test.rb +70 -0
  60. data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_top_level_pagination_test.rb +40 -0
  61. data/lib/installer_templates/example_app_tests/test/integration/example_app_apartment_versions_turbo_test.rb +120 -0
  62. data/lib/installer_templates/example_app_tests/test/integration/example_app_photo_revert_test.rb +94 -0
  63. data/lib/installer_templates/example_app_tests/test/integration/example_app_turbo_layout_test.rb +6 -9
  64. data/lib/installer_templates/example_app_tests/test/models/example_app_apartment_name_validation_test.rb +16 -0
  65. data/lib/installer_templates/example_app_tests/test/models/example_app_plain_text_rich_text_edge_cases_test.rb +46 -0
  66. data/lib/installer_templates/example_app_views/apartments/name_list.html.erb +26 -0
  67. data/lib/installer_templates/example_app_views/inline_forms/_header.html.erb +45 -0
  68. data/test/archived_form_elements_test.rb +41 -0
  69. data/test/form_element_from_callee_test.rb +2 -2
  70. data/test/inline_forms_generator_test.rb +10 -0
  71. data/test/plain_text_configuration_test.rb +90 -0
  72. metadata +45 -24
  73. data/app/views/geo_code_curacao/list_streets.html.erb +0 -1
  74. data/app/views/geo_code_curacao/list_streets.js.erb +0 -1
  75. data/app/views/inline_forms/close.js.erb +0 -4
  76. data/app/views/inline_forms/edit.js.erb +0 -1
  77. data/app/views/inline_forms/list.js.erb +0 -1
  78. data/app/views/inline_forms/new.js.erb +0 -1
  79. data/app/views/inline_forms/record_destroyed.js.erb +0 -1
  80. data/app/views/inline_forms/show.js.erb +0 -1
  81. data/app/views/inline_forms/show_element.js.erb +0 -1
  82. data/app/views/inline_forms/show_undo.js.erb +0 -1
  83. data/app/views/inline_forms/update.js.erb +0 -1
  84. data/app/views/inline_forms/versions.js.erb +0 -4
  85. data/app/views/inline_forms/versions_list.js.erb +0 -1
  86. data/lib/generators/assets/javascripts/ckeditor/config.js +0 -72
  87. /data/{app → archived/form_elements/chicas/app}/helpers/form_elements/chicas_dropdown_with_family_members.rb +0 -0
  88. /data/{app → archived/form_elements/chicas/app}/helpers/form_elements/chicas_family_photo_list.rb +0 -0
  89. /data/{app → archived/form_elements/chicas/app}/helpers/form_elements/chicas_photo_list.rb +0 -0
  90. /data/{app → archived/form_elements/geo_code_curacao/app}/controllers/geo_code_curacao_controller.rb +0 -0
  91. /data/{app → archived/form_elements/geo_code_curacao/app}/models/geo_code_curacao.rb +0 -0
  92. /data/{app → archived/form_elements/kansen_slider/app}/helpers/form_elements/kansen_slider.rb +0 -0
  93. /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
@@ -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
@@ -2,14 +2,11 @@
2
2
 
3
3
  require_relative "../example_app/example_integration_test_case"
4
4
 
5
- # Smoke test for rollout step 1 of stuff/ujs-to-turbo.md (gem-side):
6
- # the layout loads Turbo as an ES module and disables Drive so existing
7
- # UJS-driven links/forms keep working unchanged. If this asserts ever
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 with drive disabled" do
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
- assert_match(
19
+ refute_match(
23
20
  /Turbo\.session\.drive\s*=\s*false/,
24
21
  @response.body,
25
- "expected Turbo.session.drive = false so existing UJS keeps working"
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(:chicas_dropdown_with_family_members_show)
48
+ got = InlineForms.form_element_string_from_callee(:text_area_without_ckeditor_show)
49
49
  assert_equal(
50
- "chicas_dropdown_with_family_members",
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