active_element 0.0.10 → 0.0.11

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 (214) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -2
  3. data/.strong_versions.yml +1 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +108 -75
  6. data/Makefile +10 -0
  7. data/active_element.gemspec +1 -1
  8. data/app/assets/javascripts/active_element/application.js +1 -0
  9. data/app/assets/javascripts/active_element/form.js +16 -32
  10. data/app/assets/javascripts/active_element/json_field.js +391 -135
  11. data/app/assets/javascripts/active_element/setup.js +13 -8
  12. data/app/assets/javascripts/active_element/text_search_field.js +27 -28
  13. data/app/assets/javascripts/active_element/theme.js +1 -1
  14. data/app/assets/javascripts/active_element/timezones.js +6 -0
  15. data/app/assets/stylesheets/active_element/_dark.scss +86 -0
  16. data/app/assets/stylesheets/active_element/_variables.scss +2 -1
  17. data/app/assets/stylesheets/active_element/application.scss +166 -33
  18. data/app/controllers/active_element/application_controller.rb +5 -0
  19. data/app/controllers/concerns/active_element/default_controller_actions.rb +38 -0
  20. data/app/views/active_element/_user.html.erb +20 -0
  21. data/app/views/active_element/components/fields/_json.html.erb +24 -0
  22. data/app/views/active_element/components/form/_check_box.html.erb +1 -0
  23. data/app/views/active_element/components/form/_check_boxes.html.erb +1 -1
  24. data/app/views/active_element/components/form/_datetime_range_field.html.erb +14 -0
  25. data/app/views/active_element/components/form/_field.html.erb +10 -7
  26. data/app/views/active_element/components/form/_generic_field.html.erb +1 -0
  27. data/app/views/active_element/components/form/_json.html.erb +10 -2
  28. data/app/views/active_element/components/form/_label.html.erb +12 -1
  29. data/app/views/active_element/components/form/_select.html.erb +4 -1
  30. data/app/views/active_element/components/form/_summary.html.erb +11 -1
  31. data/app/views/active_element/components/form/_templates.html.erb +37 -22
  32. data/app/views/active_element/components/form/_text_area.html.erb +2 -1
  33. data/app/views/active_element/components/form/_text_search.html.erb +7 -3
  34. data/app/views/active_element/components/form.html.erb +20 -17
  35. data/app/views/active_element/components/json.html.erb +1 -0
  36. data/app/views/active_element/components/navbar.html.erb +26 -0
  37. data/app/views/active_element/components/table/_collection_row.html.erb +2 -1
  38. data/app/views/active_element/components/table/_field.html.erb +8 -0
  39. data/app/views/active_element/components/table/collection.html.erb +1 -1
  40. data/app/views/active_element/components/table/item.html.erb +5 -4
  41. data/app/views/active_element/default_views/edit.html.erb +5 -0
  42. data/app/views/active_element/default_views/index.html.erb +15 -0
  43. data/app/views/active_element/default_views/new.html.erb +4 -0
  44. data/app/views/active_element/default_views/show.html.erb +7 -0
  45. data/app/views/active_element/navbar/_menu.html.erb +1 -30
  46. data/app/views/active_element/theme/_select.html.erb +1 -1
  47. data/app/views/layouts/active_element.html.erb +16 -1
  48. data/config/brakeman.ignore +48 -0
  49. data/example_app/.gitattributes +7 -0
  50. data/example_app/.gitignore +35 -0
  51. data/example_app/.ruby-version +1 -0
  52. data/example_app/Gemfile +34 -0
  53. data/example_app/Gemfile.lock +296 -0
  54. data/example_app/README.md +24 -0
  55. data/example_app/Rakefile +6 -0
  56. data/example_app/app/assets/config/manifest.js +4 -0
  57. data/example_app/app/assets/images/.keep +0 -0
  58. data/example_app/app/assets/stylesheets/application.css +15 -0
  59. data/example_app/app/channels/application_cable/channel.rb +4 -0
  60. data/example_app/app/channels/application_cable/connection.rb +4 -0
  61. data/example_app/app/controllers/application_controller.rb +12 -0
  62. data/example_app/app/controllers/concerns/.keep +0 -0
  63. data/example_app/app/controllers/pets_controller.rb +6 -0
  64. data/example_app/app/controllers/users_controller.rb +6 -0
  65. data/example_app/app/helpers/application_helper.rb +2 -0
  66. data/example_app/app/javascript/application.js +3 -0
  67. data/example_app/app/javascript/controllers/application.js +9 -0
  68. data/example_app/app/javascript/controllers/hello_controller.js +7 -0
  69. data/example_app/app/javascript/controllers/index.js +11 -0
  70. data/example_app/app/jobs/application_job.rb +7 -0
  71. data/example_app/app/mailers/application_mailer.rb +4 -0
  72. data/example_app/app/models/application_record.rb +3 -0
  73. data/example_app/app/models/concerns/.keep +0 -0
  74. data/example_app/app/models/pet.rb +3 -0
  75. data/example_app/app/models/user.rb +8 -0
  76. data/example_app/app/views/layouts/application.html.erb +16 -0
  77. data/example_app/app/views/layouts/mailer.html.erb +13 -0
  78. data/example_app/app/views/layouts/mailer.text.erb +1 -0
  79. data/example_app/app/views/pets/index.html.erb +3 -0
  80. data/example_app/app/views/users/show.html.erb +3 -0
  81. data/example_app/bin/bundle +109 -0
  82. data/example_app/bin/importmap +4 -0
  83. data/example_app/bin/rails +4 -0
  84. data/example_app/bin/rake +4 -0
  85. data/example_app/bin/setup +33 -0
  86. data/example_app/config/application.rb +22 -0
  87. data/example_app/config/boot.rb +4 -0
  88. data/example_app/config/cable.yml +10 -0
  89. data/example_app/config/credentials.yml.enc +1 -0
  90. data/example_app/config/database.yml +25 -0
  91. data/example_app/config/environment.rb +5 -0
  92. data/example_app/config/environments/development.rb +70 -0
  93. data/example_app/config/environments/production.rb +93 -0
  94. data/example_app/config/environments/test.rb +60 -0
  95. data/example_app/config/importmap.rb +7 -0
  96. data/example_app/config/initializers/assets.rb +12 -0
  97. data/example_app/config/initializers/content_security_policy.rb +25 -0
  98. data/example_app/config/initializers/devise.rb +16 -0
  99. data/example_app/config/initializers/filter_parameter_logging.rb +8 -0
  100. data/example_app/config/initializers/inflections.rb +16 -0
  101. data/example_app/config/initializers/permissions_policy.rb +11 -0
  102. data/example_app/config/locales/devise.en.yml +65 -0
  103. data/example_app/config/locales/en.yml +33 -0
  104. data/example_app/config/puma.rb +43 -0
  105. data/example_app/config/routes.rb +8 -0
  106. data/example_app/config/storage.yml +34 -0
  107. data/example_app/config.ru +6 -0
  108. data/example_app/db/migrate/20230616210539_create_pet.rb +12 -0
  109. data/example_app/db/migrate/20230616211328_devise_create_users.rb +46 -0
  110. data/example_app/db/schema.rb +37 -0
  111. data/example_app/db/seeds.rb +33 -0
  112. data/example_app/lib/assets/.keep +0 -0
  113. data/example_app/lib/tasks/.keep +0 -0
  114. data/example_app/log/.keep +0 -0
  115. data/example_app/public/404.html +67 -0
  116. data/example_app/public/422.html +67 -0
  117. data/example_app/public/500.html +66 -0
  118. data/example_app/public/apple-touch-icon-precomposed.png +0 -0
  119. data/example_app/public/apple-touch-icon.png +0 -0
  120. data/example_app/public/favicon.ico +0 -0
  121. data/example_app/public/robots.txt +1 -0
  122. data/example_app/storage/.keep +0 -0
  123. data/example_app/test/application_system_test_case.rb +5 -0
  124. data/example_app/test/channels/application_cable/connection_test.rb +11 -0
  125. data/example_app/test/controllers/.keep +0 -0
  126. data/example_app/test/fixtures/files/.keep +0 -0
  127. data/example_app/test/fixtures/users.yml +11 -0
  128. data/example_app/test/helpers/.keep +0 -0
  129. data/example_app/test/integration/.keep +0 -0
  130. data/example_app/test/mailers/.keep +0 -0
  131. data/example_app/test/models/.keep +0 -0
  132. data/example_app/test/models/user_test.rb +7 -0
  133. data/example_app/test/system/.keep +0 -0
  134. data/example_app/test/test_helper.rb +13 -0
  135. data/example_app/tmp/.keep +0 -0
  136. data/example_app/tmp/pids/.keep +0 -0
  137. data/example_app/tmp/storage/.keep +0 -0
  138. data/example_app/vendor/.keep +0 -0
  139. data/example_app/vendor/javascript/.keep +0 -0
  140. data/lib/active_element/component.rb +9 -2
  141. data/lib/active_element/components/collection_table.rb +9 -2
  142. data/lib/active_element/components/email_fields.rb +14 -0
  143. data/lib/active_element/components/form.rb +48 -17
  144. data/lib/active_element/components/navbar.rb +64 -0
  145. data/lib/active_element/components/phone_fields.rb +14 -0
  146. data/lib/active_element/components/text_search/authorization.rb +9 -6
  147. data/lib/active_element/components/text_search/component.rb +4 -2
  148. data/lib/active_element/components/text_search.rb +4 -0
  149. data/lib/active_element/components/util/association_mapping.rb +74 -19
  150. data/lib/active_element/components/util/display_value_mapping.rb +13 -4
  151. data/lib/active_element/components/util/form_field_mapping.rb +127 -10
  152. data/lib/active_element/components/util/form_value_mapping.rb +3 -3
  153. data/lib/active_element/components/util/i18n.rb +1 -1
  154. data/lib/active_element/components/util/record_mapping.rb +43 -11
  155. data/lib/active_element/components/util/record_path.rb +21 -4
  156. data/lib/active_element/components/util.rb +12 -5
  157. data/lib/active_element/components.rb +3 -0
  158. data/lib/active_element/controller_action.rb +8 -2
  159. data/lib/active_element/controller_interface.rb +47 -5
  160. data/lib/active_element/default_controller.rb +93 -0
  161. data/lib/active_element/default_record_params.rb +62 -0
  162. data/lib/active_element/default_text_search.rb +110 -0
  163. data/lib/active_element/json_field_schema.rb +59 -0
  164. data/lib/active_element/pre_render_processors/json.rb +98 -0
  165. data/lib/active_element/pre_render_processors.rb +11 -0
  166. data/lib/active_element/route.rb +12 -0
  167. data/lib/active_element/routes.rb +2 -1
  168. data/lib/active_element/version.rb +1 -1
  169. data/lib/active_element.rb +14 -32
  170. data/lib/tasks/active_element.rake +12 -1
  171. data/rspec-documentation/_head.html.erb +34 -0
  172. data/rspec-documentation/pages/000-Introduction.md +18 -0
  173. data/rspec-documentation/pages/005-Setup.md +75 -0
  174. data/rspec-documentation/pages/010-Components/Form Fields/Check Boxes.md +1 -0
  175. data/rspec-documentation/pages/010-Components/Form Fields/JSON/Controller Params.md +97 -0
  176. data/rspec-documentation/pages/010-Components/Form Fields/JSON/Schema.md +283 -0
  177. data/rspec-documentation/pages/010-Components/Form Fields/JSON/Types.md +36 -0
  178. data/rspec-documentation/pages/010-Components/Form Fields/JSON.md +70 -0
  179. data/rspec-documentation/pages/010-Components/Form Fields/Text Search.md +133 -0
  180. data/rspec-documentation/pages/010-Components/Form Fields.md +46 -0
  181. data/rspec-documentation/pages/010-Components/Forms.md +44 -0
  182. data/rspec-documentation/pages/010-Components/JSON Data.md +23 -0
  183. data/rspec-documentation/pages/010-Components/Navbar.md +56 -0
  184. data/rspec-documentation/pages/010-Components/Page Section Title.md +13 -0
  185. data/rspec-documentation/pages/010-Components/Page Subtitle.md +11 -0
  186. data/rspec-documentation/pages/010-Components/Page Title.md +11 -0
  187. data/rspec-documentation/pages/010-Components/Tables/Collection Table.md +29 -0
  188. data/rspec-documentation/pages/010-Components/Tables/Item Table.md +18 -0
  189. data/rspec-documentation/pages/010-Components/Tables/Options.md +19 -0
  190. data/rspec-documentation/pages/010-Components/Tables.md +29 -0
  191. data/rspec-documentation/pages/010-Components.md +15 -0
  192. data/rspec-documentation/pages/020-Access Control/010-Authentication.md +20 -0
  193. data/rspec-documentation/pages/020-Access Control/020-Authorization/Environments.md +9 -0
  194. data/rspec-documentation/pages/020-Access Control/020-Authorization/Permissions/Custom Routes.md +41 -0
  195. data/rspec-documentation/pages/020-Access Control/020-Authorization/Permissions.md +58 -0
  196. data/rspec-documentation/pages/020-Access Control/020-Authorization/Setup.md +27 -0
  197. data/rspec-documentation/pages/020-Access Control/020-Authorization.md +11 -0
  198. data/rspec-documentation/pages/020-Access Control.md +31 -0
  199. data/rspec-documentation/pages/040-Decorators/Inline Decorators.md +24 -0
  200. data/rspec-documentation/pages/040-Decorators/View Decorators.md +55 -0
  201. data/rspec-documentation/pages/040-Decorators.md +12 -0
  202. data/rspec-documentation/pages/300-Alternatives.md +21 -0
  203. data/rspec-documentation/pages/900-License.md +11 -0
  204. data/rspec-documentation/spec_helper.rb +53 -16
  205. data/rspec-documentation/support.rb +84 -0
  206. metadata +155 -14
  207. data/rspec-documentation/pages/Components/Forms.md +0 -1
  208. data/rspec-documentation/pages/Components/Tables.md +0 -47
  209. data/rspec-documentation/pages/Components.md +0 -1
  210. data/rspec-documentation/pages/Decorators/Inline Decorators.md +0 -1
  211. data/rspec-documentation/pages/Decorators/View Decorators.md +0 -1
  212. data/rspec-documentation/pages/Index.md +0 -3
  213. data/rspec-documentation/pages/Util/I18n.md +0 -1
  214. /data/rspec-documentation/pages/{Components → 010-Components}/Tabs.md +0 -0
@@ -1,24 +1,27 @@
1
1
  <% if type == :select %>
2
2
  <%= render partial: 'active_element/components/form/select',
3
- locals: { form: form, field: field, options: options, component: component } %>
3
+ locals: { form_id: id, form: form, field: field, options: options, component: component } %>
4
4
  <% elsif type == :check_boxes %>
5
5
  <%= render partial: 'active_element/components/form/check_boxes',
6
- locals: { field: field, form: form, options: options, component: component } %>
6
+ locals: { form_id: id, form: form, field: field, options: options, component: component } %>
7
7
  <% elsif type == :json_field %>
8
8
  <%= render partial: 'active_element/components/form/json',
9
- locals: { field: field, form: form, options: options, component: component } %>
9
+ locals: { form_id: id, form: form, field: field, field_id: ActiveElement.element_id, options: options, component: component } %>
10
10
  <% elsif type == :text_search_field %>
11
11
  <%= render partial: 'active_element/components/form/text_search',
12
- locals: { form_id: id, field: field, form: form, options: options, component: component } %>
12
+ locals: { form_id: id, form: form, field: field, options: options, component: component } %>
13
13
  <% elsif type == :check_box %>
14
14
  <%= render partial: 'active_element/components/form/check_box',
15
- locals: { form: form, type: type, field: field, options: options, component: component } %>
15
+ locals: { form_id: id, form: form, field: field, type: type, options: options, component: component } %>
16
16
  <% elsif type == :text_area %>
17
17
  <%= render partial: 'active_element/components/form/text_area',
18
- locals: { form: form, type: type, field: field, options: options, component: component } %>
18
+ locals: { form_id: id, form: form, field: field, type: type, options: options, component: component } %>
19
+ <% elsif type == :datetime_range_field %>
20
+ <%= render partial: 'active_element/components/form/datetime_range_field',
21
+ locals: { form_id: id, form: form, field: field, type: type, options: options, component: component } %>
19
22
  <% else %>
20
23
  <%= render partial: 'active_element/components/form/generic_field',
21
- locals: { form: form, type: type, field: field, options: options, component: component } %>
24
+ locals: { form_id: id, form: form, field: field, type: type, options: options, component: component } %>
22
25
  <% end %>
23
26
 
24
27
  <% unless component.valid?(field) %>
@@ -1,3 +1,4 @@
1
1
  <%= form.public_send(type, field, value: component.value_for(field),
2
2
  class: "form-control #{component.valid?(field) ? nil : 'is-invalid'}",
3
+ tabindex: component.tabindex,
3
4
  **options) %>
@@ -1,12 +1,20 @@
1
1
  <div class="col-sm-10 json-field form-group"
2
2
  data-data-key="<%= ActiveElement::Components::Util.json_name("#{form.object_name}.#{field}") %>"
3
+ data-field-name="<%= field %>"
4
+ data-form-id="<%= form_id %>"
5
+ data-field-id="<%= field_id %>"
6
+ data-schema-field-id="<%= field_id %>-schema"
3
7
  >
4
8
 
5
9
  </div>
6
10
 
11
+ <%= form.hidden_field field, name: "#{form.object_name}[#{field}]", value: '', id: field_id %>
12
+ <%= form.hidden_field field, name: "__json_field_schemas[#{form.object_name}][#{field}]", value: '', id: "#{field_id}-schema" %>
13
+ <%= form.hidden_field field, name: '__json_fields[]', value: "#{form.object_name}.#{field}" %>
14
+
7
15
  <%=
8
- component.json(
16
+ active_element.component.json(
9
17
  ActiveElement::Components::Util.json_name("#{form.object_name}.#{field}"),
10
- { data: component.value_for(field, options), schema: component.schema_for(field, options) }
18
+ { data: component.value_for(field, default: options), schema: component.schema_for(field, options) }
11
19
  )
12
20
  %>
@@ -1,9 +1,20 @@
1
1
  <%= form.label field do %>
2
2
  <%= options[:label] %>
3
- <% if options[:description].present? %>
3
+ <% if options[:required] %>
4
4
  <button type="button"
5
5
  style="background: none; border: none; outline: 0; position: absolute; margin-top: 0.3rem"
6
+ data-bs-trigger="focus"
7
+ data-bs-toggle="popover"
8
+ title="Required"
9
+ data-bs-content="<%= "#{options.fetch(:label)} is a required field." %>"
10
+ <i class="text-secondary fa-solid fa-star-of-life"></i>
11
+ </button>
12
+ <% end %>
13
+ <% if options[:description].present? %>
14
+ <button type="button"
15
+ style="background: none; border: none; outline: 0; position: absolute; <%= options[:required] ? 'margin-left: 1.4rem;' : nil %> margin-top: 0.3rem"
6
16
  data-bs-toggle="popover"
17
+ data-bs-trigger="focus"
7
18
  title="<%= options.fetch(:label) %>"
8
19
  data-bs-content="<%= options[:description] %>">
9
20
  <i class="text-secondary fa-solid fa-circle-info"></i>
@@ -1,4 +1,7 @@
1
1
  <%= form.select field,
2
2
  component.options_for_select(field, options),
3
3
  { selected: component.value_for(field) },
4
- { class: "form-select #{component.valid?(field) ? nil : 'is-invalid'}" } %>
4
+ {
5
+ tabindex: component.tabindex,
6
+ class: "form-select #{component.valid?(field) ? nil : 'is-invalid'}"
7
+ } %>
@@ -21,7 +21,17 @@
21
21
  <span class="ms-1"><%= value %></span>
22
22
  </div>
23
23
  <% end %>
24
- <% elsif value.present? %>
24
+ <% elsif type == :datetime_range_field %>
25
+ <% next unless value.present? %>
26
+
27
+ <% values << value %>
28
+ <div class="d-inline me-3">
29
+ <span class="text-secondary"><%= options.fetch(:label) %>:</span>
30
+ <span class="ms-1 text-primary"><%= value[:from] %></span>
31
+ <span class="text-secondary">&rarr;</span>
32
+ <span class="ms-1 text-primary"><%= value[:to] %></span>
33
+ </div>
34
+ <% elsif value.class && value.present? %>
25
35
  <%# TODO: Handle other field types %>
26
36
 
27
37
  <% values << value %>
@@ -7,42 +7,62 @@
7
7
  <label id="json-form-check-label-template" class="form-check-label"></label>
8
8
  <label id="json-label-template" class="mb-4 fw-bold"></label>
9
9
 
10
- <div id="json-form-group-template" class="form-group p-3 text-wrap m-3"></div>
11
- <div id="json-form-group-floating-template" class="form-floating m-3 text-wrap"></div>
10
+ <div id="json-form-group-template" class="form-group text-wrap m-3"></div>
11
+ <div id="json-form-group-floating-template" class="form-floating m-3 text-wrap collapsed"></div>
12
12
  <div id="json-form-check-template" class="form-check m-3"></div>
13
13
 
14
14
  <input id="json-checkbox-field-template" type="checkbox" class="form-check-input json-checkbox-field" />
15
15
 
16
16
  <input id="json-text-field-template" type="text" class="form-control m-1 json-text-field" />
17
+ <input id="json-date-field-template" type="date" class="form-control m-1 d-inline-block json-date-field" />
18
+ <input id="json-time-field-template" type="time" class="form-control m-1 d-inline-block json-time-field" />
19
+ <input id="json-datetime-field-template" type="datetime-local" class="form-control m-1 d-inline-block json-datetime-field" />
20
+ <input id="json-integer-field-template" type="number" class="form-control m-1 json-integer-field" />
21
+ <input id="json-float-field-template" type="number" class="form-control m-1 json-float-field" />
22
+ <input id="json-decimal-field-template" type="number" class="form-control m-1 json-decimal-field" />
17
23
 
18
24
  <select id="json-select-template" class="form-select m-1 json-select-field"></select>
19
25
 
20
26
  <%= active_element.component.destroy_button id: 'json-delete-button-template',
21
- class: 'button-sm json-delete-button' %>
27
+ class: 'btn-sm json-delete-button', data: { 'confirm-action': 'false' } %>
22
28
 
23
29
  <%= active_element.component.button 'Delete Item', type: 'danger', id: 'json-delete-object-button-template',
24
- class: 'json-delete-button w-25 float-end json-delete-object-button' %>
30
+ style: 'z-index: 1500',
31
+ class: 'btn-sm json-delete-button float-end json-delete-object-button' %>
25
32
 
26
33
  <%= active_element.component.button id: 'json-append-button-template',
27
- class: 'btn-sm mt-3 mb-3 json-add-field-button' %>
34
+ class: 'btn-sm json-add-field-button' %>
28
35
 
29
36
  <%= active_element.component.button 'Hide', id: 'json-expand-collapse-button-template',
30
37
  class: 'float-end expand-collapse-button' %>
31
38
 
39
+ <div id="json-focus-template" class="focus m-1"></div>
40
+ <i id="json-focus-expand-template" class="fa-solid fa-fw fa-plus"></i>
41
+ <i id="json-focus-collapse-template" class="fa-solid fa-fw fa-minus d-none"></i>
42
+ <div id="json-modal-template"
43
+ class="modal fade"
44
+ tabindex="-1"
45
+ aria-hidden="true">
46
+ <div class="modal-dialog modal-dialog-centered modal-xl modal-dialog-scrollable json-field-modal">
47
+ <div class="modal-content">
48
+ <div class="modal-header">
49
+ <h5 class="modal-title" data-field-type="modal-title"></h5>
50
+ <div class="modal-buttons">
51
+ <button type="button" class="btn btn-primary btn-sm me-2" data-bs-dismiss="modal" aria-label="Finish Editing">
52
+ Finish Editing
53
+ </button>
54
+ </div>
55
+ </div>
56
+ <div class="modal-body" data-field-type="modal-body"></div>
57
+ <div class="modal-footer" data-field-type="modal-footer"></div>
58
+ </div>
59
+ </div>
60
+ </div>
32
61
  </div>
33
62
 
34
- <%= active_element.component.button 'Expand Form', id: 'form-expand-button-template', class: 'mb-1 btn-sm' do %>
35
- <i class="fa-solid fa-fw fa-up-right-and-down-left-from-center"></i>
36
- <% end %>
37
-
38
- <%= active_element.component.button 'Collapse Form', id: 'form-collapse-button-template', class: 'mb-1 btn-sm' do %>
39
- <i class="fa-solid fa-fw fa-down-left-and-up-right-to-center"></i>
40
- <% end %>
41
-
42
63
 
43
64
  <div id="form-search-field-templates">
44
- <input id="form-search-field-hidden-input-template" type="hidden" autocomplete="off" />
45
- <p id="form-search-field-response-error-template" class="text-danger position-absolute validation-error-message pt-1 m-0"></p>
65
+ <p id="form-search-field-response-error-template" class="text-danger validation-error-message pt-1 m-0"></p>
46
66
  <div id="form-search-field-results-template" class="search-field-results d-none border border-top-0"></div>
47
67
  <div id="form-search-field-results-item-template" class="search-field-result p-2"></div>
48
68
  <div id="form-search-field-spinner-template" class="invisible text-end">
@@ -50,11 +70,6 @@
50
70
  <i class="fa-solid fa-spinner fa-spin"></i>
51
71
  </div>
52
72
  </div>
53
- <div id="form-search-field-clear-button-template" class="invisible text-end">
54
- <div style="position: relative; float: right; width: auto; right: 0.5rem; top: -1.7rem;">
55
- <i class="fa-solid fa-delete-left" style="cursor: pointer;"></i>
56
- </div>
57
- </div>
58
73
  </div>
59
74
 
60
75
  <div id="form-modal-template"
@@ -65,8 +80,8 @@
65
80
  <div class="modal-content">
66
81
  <div class="modal-header">
67
82
  <h5 class="modal-title" data-field-type="modal-title"></h5>
68
- <button type="button" class="btn-close fs-3" data-bs-dismiss="modal" aria-label="Close">
69
- <i class="fa-regular fa-rectangle-xmark"></i>
83
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
84
+ <i class="fa-solid fa-xmark"></i>
70
85
  </button>
71
86
  </div>
72
87
  <div class="modal-body" data-field-type="modal-body"></div>
@@ -1,4 +1,5 @@
1
1
  <%= form.text_area field,
2
2
  value: component.value_for(field),
3
- rows: 5,
3
+ rows: options.fetch(:rows, 5),
4
+ tabindex: component.tabindex,
4
5
  class: "form-control #{component.valid?(field) ? nil : 'is-invalid'}" %>
@@ -1,16 +1,20 @@
1
1
  <%=
2
- form.text_field field, value: component.value_for(field),
2
+ form.text_field field, value: options.fetch(:display_value) { component.value_for(field) },
3
3
  id: "#{form_id}-#{field}-text-search",
4
4
  class: "form-control #{component.valid?(field) ? nil : 'is-invalid'}",
5
5
  autocomplete: 'off',
6
6
  placeholder: options[:placeholder].presence || 'Search...',
7
+ tabindex: component.tabindex,
7
8
  data: {
8
9
  field_type: 'text-search',
9
10
  form_id: form_id,
10
11
  search_attributes: (
11
- options.dig(:search, :attributes) || [options.dig(:search, :attribute)]
12
+ options.dig(:search, :with) || [options.dig(:search, :with)]
12
13
  )&.to_json,
13
- search_value: options.dig(:search, :value),
14
+ search_value: options.dig(:search, :providing),
14
15
  search_model: options.dig(:search, :model)
15
16
  }
16
17
  %>
18
+
19
+ <%= form.hidden_field field, id: "#{form_id}-#{field}-text-search-hidden-value",
20
+ value: component.value_for(field) %>
@@ -1,5 +1,7 @@
1
1
  <% if destroy %>
2
- <%= active_element.component.destroy_button(record, float: 'end') %>
2
+ <div class="container w-100 text-end">
3
+ <%= active_element.component.destroy_button(record) %>
4
+ </div>
3
5
  <% end %>
4
6
 
5
7
  <% if modal %>
@@ -20,32 +22,32 @@
20
22
 
21
23
  </div>
22
24
 
23
- <% elsif title.present? && expanded == false %>
24
-
25
- <div data-field-type="form-expand" data-form-id="<%= id %>" class="mb-3">
26
- <span class="fs-4 align-bottom"><%= title %></span>
27
- </div>
28
-
29
- <% elsif title.blank? && expanded == false %>
30
-
31
- <div data-field-type="form-expand" data-form-id="<%= id %>" class="mb-3"></div>
32
-
33
25
  <% elsif title.present? %>
34
26
 
35
27
  <span class="fs-4 align-bottom"><%= title %></span>
36
28
 
37
29
  <% end %>
38
30
 
39
- <div class="expand-collapse-form <%= modal ? 'd-none' : nil %>" id="form-wrapper-<%= id %>">
40
- <%= form_with local: true, **kwargs, method: method, id: id, class: "#{class_name} m-3 #{modal == false && expanded == false ? 'd-none' : nil}" do |form| %>
31
+ <% unless component.valid? %>
32
+ <p class="text-danger pt-1 m-0 validation-error-message">
33
+ <%= component.full_error_message %>
34
+ </p>
35
+ <% end %>
36
+
37
+ <div class="form <%= modal ? 'd-none' : 'pb-3' %>" id="form-wrapper-<%= id %>">
38
+ <%= form_with local: true, action: action, method: method, id: id, class: "#{class_name} m-3", **kwargs do |form| %>
41
39
  <% if %i[top both].include?(submit_position) %>
42
- <div class="form-group sticky-top" style="top: 0.5rem;">
43
- <%= form.submit submit_label, class: "btn btn-#{method == :post ? 'success' : 'primary'} float-end" %>
40
+ <div class="row mb-3 form-group sticky-top" style="top: 0.5rem;">
41
+ <div class="col-sm-3"></div>
42
+ <div class="col pb-3">
43
+ <%= form.submit submit_label, name: '', class: "btn btn-#{method == :post ? 'success' : 'primary'} ms-2 float-end" %>
44
+ <%= active_element.component.button 'Clear Form', class: 'btn-secondary float-end', data: { 'form-input-type': 'clear' } %>
45
+ </div>
44
46
  </div>
45
47
  <% end %>
46
48
 
47
49
  <% fields.each_slice(columns) do |field_group| %>
48
- <div class="row mb-3">
50
+ <div class="row form-fields mb-3">
49
51
  <% field_group.each do |field, type, options| %>
50
52
  <div class="col-sm-3">
51
53
  <%= render partial: 'active_element/components/form/label',
@@ -71,7 +73,8 @@
71
73
 
72
74
  <% if %i[bottom both].include?(submit_position) %>
73
75
  <div class="form-group">
74
- <%= form.submit submit_label, class: "btn btn-#{method == :post ? 'success' : 'primary'}" %>
76
+ <%= form.submit submit_label, name: '', class: "btn btn-#{method == :post ? 'success' : 'primary'}" %>
77
+ <%= active_element.component.button 'Clear Form', class: 'btn-secondary ms-2', data: { 'form-input-type': 'clear' } %>
75
78
  </div>
76
79
  <% end %>
77
80
  <% end %>
@@ -1,4 +1,5 @@
1
1
  <script type="text/javascript">
2
+ window.ActiveElement = window.ActiveElement || {};
2
3
  ActiveElement.jsonData = ActiveElement.jsonData || {};
3
4
 
4
5
  ActiveElement.jsonData = {
@@ -0,0 +1,26 @@
1
+ <div class="application-menu <%= fixed ? 'position-fixed' : nil %> w-100 navbar navbar-dark bg-dark navbar-expand-lg">
2
+ <div class="container">
3
+ <a class="navbar-brand" href="#"><%= ActiveElement.application_title %></a>
4
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
5
+ <span class="navbar-toggler-icon"></span>
6
+ </button>
7
+ <div class="collapse navbar-collapse" id="navbarSupportedContent">
8
+ <ul class="navbar-nav me-auto mb-2 mb-lg-0">
9
+ <% items.each do |navbar_item| %>
10
+ <li class="nav-item">
11
+ <%=
12
+ link_to navbar_item.fetch(:title) { navbar_item.fetch(:label) },
13
+ navbar_item.fetch(:path),
14
+ class: "nav-link #{component.active_path_class(current_navbar_item: navbar_item)}"
15
+ %>
16
+ </li>
17
+ <% end %>
18
+ </li>
19
+ </ul>
20
+ </div>
21
+ </div>
22
+ <div class="d-flex icon-menu p-3">
23
+ <%= render partial: 'active_element/user' %>
24
+ <%= render partial: 'active_element/theme/select' %>
25
+ </div>
26
+ </div>
@@ -5,7 +5,8 @@
5
5
  <%= controller.helpers.render partial: 'active_element/components/secret/field',
6
6
  locals: { secret: value_mapper.call(item), label: label } %>
7
7
  <% else %>
8
- <%= value_mapper.call(item) %>
8
+ <%= controller.helpers.render partial: 'active_element/components/table/field',
9
+ locals: { value: value_mapper.call(item) } %>
9
10
  <% end %>
10
11
  </td>
11
12
  <% end %>
@@ -0,0 +1,8 @@
1
+ <% if value.is_a?(Array) %>
2
+ <% value.each_with_index do |each_value, index| %>
3
+ <%= each_value %>
4
+ <%= index < value.size - 1 ? '|' : nil %>
5
+ <% end %>
6
+ <% else %>
7
+ <%= value %>
8
+ <% end %>
@@ -1,5 +1,5 @@
1
1
  <% if new %>
2
- <%= active_element.component.new_button(collection, float: 'end', class: 'mb-3') %>
2
+ <%= active_element.component.new_button(component.model&.new, float: 'end', class: 'mb-3') %>
3
3
  <% end %>
4
4
 
5
5
  <% if display_pagination %>
@@ -7,7 +7,7 @@
7
7
  <% end %>
8
8
 
9
9
  <% if new %>
10
- <%= active_element.component.new_button(item, float: 'end', class: 'mb-3') %>
10
+ <%= active_element.component.new_button(component.model, float: 'end', class: 'mb-3') %>
11
11
  <% end %>
12
12
 
13
13
  <table class="<%= class_name %> table" style="<%= style %>">
@@ -27,10 +27,11 @@
27
27
  </th>
28
28
  <td class="<%= class_mapper.call(item) %>">
29
29
  <% if component.secret_field?(field) %>
30
- <%= controller.helpers.render partial: 'active_element/components/secret/field',
31
- locals: { secret: value_mapper.call(item), label: label } %>
30
+ <%= render partial: 'active_element/components/secret/field',
31
+ locals: { secret: value_mapper.call(item), label: label } %>
32
32
  <% else %>
33
- <%= value_mapper.call(item) %>
33
+ <%= render partial: 'active_element/components/table/field',
34
+ locals: { value: value_mapper.call(item) } %>
34
35
  <% end %>
35
36
  </td>
36
37
  </tr>
@@ -0,0 +1,5 @@
1
+ <%= active_element.component.page_title record.model_name.to_s.titleize %>
2
+
3
+ <%= active_element.component.form model: [namespace, record].compact,
4
+ destroy: true,
5
+ fields: active_element.state.fetch(:editable_fields, []) %>
@@ -0,0 +1,15 @@
1
+ <% if active_element.state.key?(:searchable_fields) %>
2
+ <%= active_element.component.form title: 'Search Filters',
3
+ submit: 'Search',
4
+ modal: true,
5
+ search: true,
6
+ item: search_filters,
7
+ fields: active_element.state.fetch(:searchable_fields) %>
8
+ <% end %>
9
+
10
+ <%= active_element.component.table new: true,
11
+ show: true,
12
+ edit: true,
13
+ destroy: true,
14
+ collection: collection,
15
+ fields: active_element.state.fetch(:listable_fields, []) %>
@@ -0,0 +1,4 @@
1
+ <%= active_element.component.page_title record.model_name.to_s.titleize %>
2
+
3
+ <%= active_element.component.form model: [namespace, record].compact,
4
+ fields: active_element.state.fetch(:editable_fields, []) %>
@@ -0,0 +1,7 @@
1
+ <%= active_element.component.page_title record.model_name.to_s.titleize %>
2
+
3
+ <%= active_element.component.table item: record,
4
+ edit: true,
5
+ destroy: true,
6
+ fields: active_element.state.fetch(:viewable_fields, []) %>
7
+
@@ -1,30 +1 @@
1
- <div class="application-menu position-fixed w-100 navbar navbar-dark bg-dark navbar-expand-lg">
2
- <%= render partial: 'active_element/theme/select' %>
3
- <div class="container p-0">
4
- <a class="navbar-brand" href="#"><%= ActiveElement.application_title %></a>
5
- <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
6
- <span class="navbar-toggler-icon"></span>
7
- </button>
8
- <div class="collapse navbar-collapse" id="navbarSupportedContent">
9
- <ul class="navbar-nav me-auto mb-2 mb-lg-0">
10
- <% ActiveElement.navbar_items(active_element.current_user).each do |navbar_item| %>
11
- <li class="nav-item">
12
- <%=
13
- link_to navbar_item.fetch(:title) { navbar_item.fetch(:label) },
14
- navbar_item.fetch(:path),
15
- class: "nav-link #{
16
- ActiveElement.active_path_class(
17
- user: active_element.current_user,
18
- current_navbar_item: navbar_item,
19
- current_path: request.path,
20
- controller_path: controller_path,
21
- action_name: action_name)
22
- }"
23
- %>
24
- </li>
25
- <% end %>
26
- </li>
27
- </ul>
28
- </div>
29
- </div>
30
- </div>
1
+ <%= ActiveElement.component.navbar(items: ActiveElement.navbar_items) %>
@@ -1 +1 @@
1
- <div id="theme-select"></div>
1
+ <div class="ms-2" id="theme-select"></div>
@@ -2,6 +2,21 @@
2
2
  <head>
3
3
  <%= render_active_element_hook 'active_element/before_head' %>
4
4
 
5
+ <style>
6
+ <%= Rouge::Theme.find('tulip').render(scope: '.json-highlight') %>
7
+ .json-highlight .p {
8
+ color: #7e4b6f;
9
+ }
10
+
11
+ .json-highlight .s2 {
12
+ color: #6b7399
13
+ }
14
+
15
+ .json-highlight {
16
+ background-color: transparent;
17
+ }
18
+ </style>
19
+
5
20
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
6
21
  <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js" integrity="sha512-fD9DI5bZwQxOi7MhYWnnNPlvXdp/2Pj3XSTRrFs5FQa4mizyGLnJcN6tuvUS6LbmgN1ut+XGSABKvjN0H6Aoow==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
7
22
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.9.2/umd/popper.min.js" integrity="sha512-2rNj2KJ+D8s1ceNasTIex6z4HWyOnEYLVC3FigGOmyQCZc2eBXKgOxQmo3oKLHyfcj53uz4QMsRCWNbLd32Q1g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
@@ -25,7 +40,7 @@
25
40
 
26
41
  <body>
27
42
  <%= render_active_element_hook 'active_element/before_navbar' %>
28
- <%= render partial: 'active_element/navbar/menu' %>
43
+ <%= active_element.component.navbar(items: ActiveElement.navbar_items) %>
29
44
  <%= render_active_element_hook 'active_element/after_navbar' %>
30
45
 
31
46
  <% flash.each do |type, message| %>
@@ -0,0 +1,48 @@
1
+ {
2
+ "ignored_warnings": [
3
+ {
4
+ "warning_type": "SQL Injection",
5
+ "warning_code": 0,
6
+ "fingerprint": "7d17f93e2d87d1f9dc0fbf6e4ce46856e4fb0e1f99a7e0ce4ea3ed73be68efc4",
7
+ "check_name": "SQL",
8
+ "message": "Possible SQL injection",
9
+ "file": "lib/active_element/json_field_schema.rb",
10
+ "line": 21,
11
+ "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
12
+ "code": "ActiveRecord::Base.connection.execute(\"select #{column} from #{table}\")",
13
+ "render_path": null,
14
+ "location": {
15
+ "type": "method",
16
+ "class": "ActiveElement::JsonFieldSchema",
17
+ "method": "data"
18
+ },
19
+ "user_input": "column",
20
+ "confidence": "Medium",
21
+ "cwe_id": [
22
+ 89
23
+ ],
24
+ "note": ""
25
+ },
26
+ {
27
+ "warning_type": "Unmaintained Dependency",
28
+ "warning_code": 121,
29
+ "fingerprint": "edf687f759ec9765bd5db185dbc615c80af77d6e7e19386fc42934e7a80307af",
30
+ "check_name": "EOLRuby",
31
+ "message": "Support for Ruby 2.7.8 ended on 2023-03-31",
32
+ "file": ".ruby-version",
33
+ "line": 1,
34
+ "link": "https://brakemanscanner.org/docs/warning_types/unmaintained_dependency/",
35
+ "code": null,
36
+ "render_path": null,
37
+ "location": null,
38
+ "user_input": null,
39
+ "confidence": "High",
40
+ "cwe_id": [
41
+ 1104
42
+ ],
43
+ "note": ""
44
+ }
45
+ ],
46
+ "updated": "2023-06-10 13:50:20 +0100",
47
+ "brakeman_version": "5.4.1"
48
+ }
@@ -0,0 +1,7 @@
1
+ # See https://git-scm.com/docs/gitattributes for more about git attribute files.
2
+
3
+ # Mark the database schema as having been generated.
4
+ db/schema.rb linguist-generated
5
+
6
+ # Mark any vendored files as having been vendored.
7
+ vendor/* linguist-vendored
@@ -0,0 +1,35 @@
1
+ # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore bundler config.
8
+ /.bundle
9
+
10
+ # Ignore the default SQLite database.
11
+ /db/*.sqlite3
12
+ /db/*.sqlite3-*
13
+
14
+ # Ignore all logfiles and tempfiles.
15
+ /log/*
16
+ /tmp/*
17
+ !/log/.keep
18
+ !/tmp/.keep
19
+
20
+ # Ignore pidfiles, but keep the directory.
21
+ /tmp/pids/*
22
+ !/tmp/pids/
23
+ !/tmp/pids/.keep
24
+
25
+ # Ignore uploaded files in development.
26
+ /storage/*
27
+ !/storage/.keep
28
+ /tmp/storage/*
29
+ !/tmp/storage/
30
+ !/tmp/storage/.keep
31
+
32
+ /public/assets
33
+
34
+ # Ignore master key for decrypting credentials and more.
35
+ /config/master.key
@@ -0,0 +1 @@
1
+ 2.7.8