active_element 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
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