active_element 0.0.1 → 0.0.3

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -0
  3. data/.strong_versions.yml +2 -0
  4. data/Gemfile +10 -2
  5. data/Gemfile.lock +229 -4
  6. data/Rakefile +1 -0
  7. data/active_element.gemspec +7 -0
  8. data/app/assets/config/active_element/manifest.js +2 -0
  9. data/app/assets/javascripts/active_element/application.js +10 -0
  10. data/app/assets/javascripts/active_element/confirm.js +67 -0
  11. data/app/assets/javascripts/active_element/form.js +61 -0
  12. data/app/assets/javascripts/active_element/json_field.js +316 -0
  13. data/app/assets/javascripts/active_element/pagination.js +18 -0
  14. data/app/assets/javascripts/active_element/search_field.js +127 -0
  15. data/app/assets/javascripts/active_element/secret.js +40 -0
  16. data/app/assets/javascripts/active_element/setup.js +36 -0
  17. data/app/assets/javascripts/active_element/theme.js +42 -0
  18. data/app/assets/stylesheets/active_element/_variables.scss +142 -0
  19. data/app/assets/stylesheets/active_element/application.scss +77 -0
  20. data/app/controllers/active_element/application_controller.rb +41 -0
  21. data/app/controllers/active_element/text_searches_controller.rb +189 -0
  22. data/app/views/active_element/components/_horizontal_tabs.html.erb +32 -0
  23. data/app/views/active_element/components/_vertical_tabs.html.erb +38 -0
  24. data/app/views/active_element/components/button.html.erb +27 -0
  25. data/app/views/active_element/components/fields/_boolean.html.erb +11 -0
  26. data/app/views/active_element/components/form/_check_box.html.erb +3 -0
  27. data/app/views/active_element/components/form/_check_boxes.html.erb +33 -0
  28. data/app/views/active_element/components/form/_field.html.erb +28 -0
  29. data/app/views/active_element/components/form/_generic_field.html.erb +3 -0
  30. data/app/views/active_element/components/form/_json.html.erb +12 -0
  31. data/app/views/active_element/components/form/_label.html.erb +17 -0
  32. data/app/views/active_element/components/form/_option_groups_summary.html.erb +17 -0
  33. data/app/views/active_element/components/form/_select.html.erb +4 -0
  34. data/app/views/active_element/components/form/_summary.html.erb +40 -0
  35. data/app/views/active_element/components/form/_templates.html.erb +85 -0
  36. data/app/views/active_element/components/form/_text_area.html.erb +4 -0
  37. data/app/views/active_element/components/form/_text_search.html.erb +16 -0
  38. data/app/views/active_element/components/form.html.erb +78 -0
  39. data/app/views/active_element/components/json.html.erb +8 -0
  40. data/app/views/active_element/components/page_description.html.erb +3 -0
  41. data/app/views/active_element/components/secret/_field.html.erb +1 -0
  42. data/app/views/active_element/components/secret/_templates.html.erb +11 -0
  43. data/app/views/active_element/components/table/_collection_row.html.erb +30 -0
  44. data/app/views/active_element/components/table/_grouped_collection.html.erb +88 -0
  45. data/app/views/active_element/components/table/_pagination.html.erb +17 -0
  46. data/app/views/active_element/components/table/_ungrouped_collection.html.erb +49 -0
  47. data/app/views/active_element/components/table/collection.html.erb +39 -0
  48. data/app/views/active_element/components/table/item.html.erb +39 -0
  49. data/app/views/active_element/components/tabs.html.erb +7 -0
  50. data/app/views/active_element/decorators/_boolean.html.erb +5 -0
  51. data/app/views/active_element/decorators/_date.html.erb +3 -0
  52. data/app/views/active_element/decorators/_datetime.html.erb +3 -0
  53. data/app/views/active_element/decorators/_time.html.erb +3 -0
  54. data/app/views/active_element/forbidden.html.erb +33 -0
  55. data/app/views/active_element/main_menu/_item.html.erb +9 -0
  56. data/app/views/active_element/navbar/_menu.html.erb +30 -0
  57. data/app/views/active_element/theme/_select.html.erb +1 -0
  58. data/app/views/active_element/theme/_templates.html.erb +6 -0
  59. data/app/views/kaminari/_first_page.html.erb +3 -0
  60. data/app/views/kaminari/_gap.html.erb +3 -0
  61. data/app/views/kaminari/_last_page.html.erb +3 -0
  62. data/app/views/kaminari/_next_page.html.erb +3 -0
  63. data/app/views/kaminari/_page.html.erb +9 -0
  64. data/app/views/kaminari/_paginator.html.erb +17 -0
  65. data/app/views/kaminari/_prev_page.html.erb +3 -0
  66. data/app/views/layouts/active_element.html.erb +65 -0
  67. data/app/views/layouts/active_element_error.html.erb +40 -0
  68. data/config/routes.rb +5 -0
  69. data/lib/active_element/active_menu_link.rb +80 -0
  70. data/lib/active_element/active_record_text_search_authorization.rb +12 -0
  71. data/lib/active_element/colorized_string.rb +33 -0
  72. data/lib/active_element/component.rb +122 -0
  73. data/lib/active_element/components/button.rb +156 -0
  74. data/lib/active_element/components/collection_table.rb +118 -0
  75. data/lib/active_element/components/form.rb +210 -0
  76. data/lib/active_element/components/item_table.rb +57 -0
  77. data/lib/active_element/components/json.rb +31 -0
  78. data/lib/active_element/components/link_helpers.rb +9 -0
  79. data/lib/active_element/components/page_description.rb +28 -0
  80. data/lib/active_element/components/secret_fields.rb +15 -0
  81. data/lib/active_element/components/tab.rb +37 -0
  82. data/lib/active_element/components/tabs.rb +35 -0
  83. data/lib/active_element/components/translations.rb +18 -0
  84. data/lib/active_element/components/util/association_mapping.rb +80 -0
  85. data/lib/active_element/components/util/decorator.rb +107 -0
  86. data/lib/active_element/components/util/display_value_mapping.rb +48 -0
  87. data/lib/active_element/components/util/field_mapping.rb +144 -0
  88. data/lib/active_element/components/util/form_field_mapping.rb +104 -0
  89. data/lib/active_element/components/util/form_value_mapping.rb +49 -0
  90. data/lib/active_element/components/util/i18n.rb +66 -0
  91. data/lib/active_element/components/util/record_mapping.rb +111 -0
  92. data/lib/active_element/components/util.rb +43 -0
  93. data/lib/active_element/components.rb +20 -0
  94. data/lib/active_element/controller_action.rb +91 -0
  95. data/lib/active_element/engine.rb +26 -0
  96. data/lib/active_element/permissions_check.rb +101 -0
  97. data/lib/active_element/rails_component.rb +40 -0
  98. data/lib/active_element/route.rb +112 -0
  99. data/lib/active_element/routes.rb +62 -0
  100. data/lib/active_element/version.rb +1 -1
  101. data/lib/active_element.rb +91 -1
  102. data/lib/tasks/active_element.rake +23 -0
  103. data/rspec-documentation/dummy +1 -0
  104. data/rspec-documentation/pages/Components/Forms.md +1 -0
  105. data/rspec-documentation/pages/Components/Tables.md +47 -0
  106. data/rspec-documentation/pages/Components/Tabs.md +1 -0
  107. data/rspec-documentation/pages/Components.md +1 -0
  108. data/rspec-documentation/pages/Decorators/Inline Decorators.md +1 -0
  109. data/rspec-documentation/pages/Decorators/View Decorators.md +1 -0
  110. data/rspec-documentation/pages/Index.md +3 -0
  111. data/rspec-documentation/pages/Util/I18n.md +1 -0
  112. data/rspec-documentation/spec_helper.rb +35 -0
  113. metadata +191 -3
@@ -0,0 +1,40 @@
1
+ <% values = [] %>
2
+ <% fields.each do |field_name, type, options| %>
3
+ <% value = component.value_for(field_name) %>
4
+
5
+ <% if type == :check_box %>
6
+
7
+ <% if ['1', true].include?(value) %>
8
+ <% values << value %>
9
+ <div class="d-inline me-3">
10
+ <i class="text-success fa-regular fa-fw fa-circle-check"></i>
11
+ <span><%= options.fetch(:label) %></span>
12
+ </div>
13
+ <% end %>
14
+
15
+ <% elsif type == :select %>
16
+ <% value = component.display_value_for_select(field_name, options) %>
17
+ <% if value.present? %>
18
+ <% values << value %>
19
+ <div class="d-inline me-3">
20
+ <span class="text-secondary"><%= options.fetch(:label) %>:</span>
21
+ <span class="ms-1"><%= value %></span>
22
+ </div>
23
+ <% end %>
24
+ <% elsif value.present? %>
25
+ <%# TODO: Handle other field types %>
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"><%= value %></span>
31
+ </div>
32
+
33
+ <% end %>
34
+ <% end %>
35
+
36
+ <% if values.empty? %>
37
+ <div class="d-inline ms-3 me-3">
38
+ <span class="fst-italic text-secondary">(No filters applied)</span>
39
+ </div>
40
+ <% end %>
@@ -0,0 +1,85 @@
1
+ <div class="d-none" id="form-templates">
2
+ <div id="json-templates">
3
+ <ol id="json-list-group-template"></ol>
4
+
5
+ <li id="json-list-item-template" class="text-nowrap"></li>
6
+
7
+ <label id="json-form-check-label-template" class="form-check-label"></label>
8
+ <label id="json-label-template" class="mb-4 fw-bold"></label>
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>
12
+ <div id="json-form-check-template" class="form-check m-3"></div>
13
+
14
+ <input id="json-checkbox-field-template" type="checkbox" class="form-check-input json-checkbox-field" />
15
+
16
+ <input id="json-text-field-template" type="text" class="form-control m-1 json-text-field" />
17
+
18
+ <select id="json-select-template" class="form-select m-1 json-select-field"></select>
19
+
20
+ <%= active_element_component.destroy_button id: 'json-delete-button-template',
21
+ class: 'button-sm json-delete-button' %>
22
+
23
+ <%= 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' %>
25
+
26
+ <%= active_element_component.button id: 'json-append-button-template',
27
+ class: 'btn-sm mt-3 mb-3 json-add-field-button' %>
28
+
29
+ <%= active_element_component.button 'Hide', id: 'json-expand-collapse-button-template',
30
+ class: 'float-end expand-collapse-button' %>
31
+
32
+ </div>
33
+
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
+
43
+ <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>
46
+ <div id="form-search-field-results-template" class="search-field-results d-none border border-top-0"></div>
47
+ <div id="form-search-field-results-item-template" class="search-field-result p-2"></div>
48
+ <div id="form-search-field-spinner-template" class="invisible text-end">
49
+ <div style="position: relative; float: right; width: auto; right: 0.5rem; top: -1.7rem;">
50
+ <i class="fa-solid fa-spinner fa-spin"></i>
51
+ </div>
52
+ </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
+ </div>
59
+
60
+ <div id="form-modal-template"
61
+ class="modal fade"
62
+ tabindex="-1"
63
+ aria-hidden="true">
64
+ <div class="modal-dialog modal-dialog-centered modal-xl modal-dialog-scrollable">
65
+ <div class="modal-content">
66
+ <div class="modal-header">
67
+ <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>
70
+ </button>
71
+ </div>
72
+ <div class="modal-body" data-field-type="modal-body"></div>
73
+ <div class="modal-footer" data-field-type="modal-footer"></div>
74
+ </div>
75
+ </div>
76
+ </div>
77
+
78
+ <div id="form-confirm-button-template">
79
+ <%= active_element_component.button 'Confirm' %>
80
+ </div>
81
+
82
+ <div id="form-cancel-button-template">
83
+ <%= active_element_component.button 'Cancel' %>
84
+ </div>
85
+ </div>
@@ -0,0 +1,4 @@
1
+ <%= form.text_area field,
2
+ value: component.value_for(field),
3
+ rows: 5,
4
+ class: "form-control #{component.valid?(field) ? nil : 'is-invalid'}" %>
@@ -0,0 +1,16 @@
1
+ <%=
2
+ form.text_field field, value: component.value_for(field),
3
+ id: "#{form_id}-#{field}-text-search",
4
+ class: "form-control #{component.valid?(field) ? nil : 'is-invalid'}",
5
+ autocomplete: 'off',
6
+ placeholder: options[:placeholder].presence || 'Search...',
7
+ data: {
8
+ field_type: 'text-search',
9
+ form_id: form_id,
10
+ search_attributes: (
11
+ options.dig(:search, :attributes) || [options.dig(:search, :attribute)]
12
+ )&.to_json,
13
+ search_value: options.dig(:search, :value),
14
+ search_model: options.dig(:search, :model)
15
+ }
16
+ %>
@@ -0,0 +1,78 @@
1
+ <% if destroy %>
2
+ <%= active_element_component.destroy_button(record, float: 'end') %>
3
+ <% end %>
4
+
5
+ <% if modal %>
6
+
7
+ <div class="mt-4 mb-5 ms-3">
8
+
9
+ <div class="p-3 pb-4 border-bottom d-inline">
10
+ <%= active_element_component.button(
11
+ title: title.presence || 'Show Form',
12
+ icon: 'arrow-up-right-dots',
13
+ data: { field_type: 'form-modal', form_id: id, form_title: title }) %>
14
+ </div>
15
+
16
+ <div class="form-summary d-inline border-bottom border-start mt-1 p-3 pb-4">
17
+ <%= render partial: 'active_element/components/form/summary',
18
+ locals: { fields: fields, component: component } %>
19
+ </div>
20
+
21
+ </div>
22
+
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
+ <% elsif title.present? %>
34
+
35
+ <span class="fs-4 align-bottom"><%= title %></span>
36
+
37
+ <% end %>
38
+
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| %>
41
+ <% 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-success float-end' %>
44
+ </div>
45
+ <% end %>
46
+
47
+ <% fields.each_slice(columns) do |field_group| %>
48
+ <div class="row mb-3">
49
+ <% field_group.each do |field, type, options| %>
50
+ <div class="col-sm-3">
51
+ <%= render partial: 'active_element/components/form/label',
52
+ locals: { type: type, form: form, field: field, options: options } %>
53
+ </div>
54
+
55
+
56
+ <div class="col">
57
+ <%= render partial: 'active_element/components/form/field',
58
+ locals: {
59
+ id: id,
60
+ type: type,
61
+ form: form,
62
+ field: field,
63
+ options: options,
64
+ component: component,
65
+ record: record }
66
+ %>
67
+ </div>
68
+ <% end %>
69
+ </div>
70
+ <% end %>
71
+
72
+ <% if %i[bottom both].include?(submit_position) %>
73
+ <div class="form-group">
74
+ <%= form.submit submit_label, class: "btn btn-#{method == :post ? 'success' : 'primary'}" %>
75
+ </div>
76
+ <% end %>
77
+ <% end %>
78
+ </div>
@@ -0,0 +1,8 @@
1
+ <script type="text/javascript">
2
+ ActiveElement.jsonData = ActiveElement.jsonData || {};
3
+
4
+ ActiveElement.jsonData = {
5
+ ...ActiveElement.jsonData,
6
+ ...<%= raw({ key.camelize(:lower) => object }.to_json) %>
7
+ };
8
+ </script>
@@ -0,0 +1,3 @@
1
+ <div class="page-description p-2 fst-italic">
2
+ <%= content %>
3
+ </div>
@@ -0,0 +1 @@
1
+ <span data-field-type="secret" data-secret="<%= secret %>"></span>
@@ -0,0 +1,11 @@
1
+ <div class="d-none" id="secret-templates">
2
+ <span id="secret-show-button-template">
3
+ <a href="#"><i class="fa-solid fa-fw fa-eye"></i></a>
4
+ </span>
5
+
6
+ <span id="secret-hide-button-template">
7
+ <a href="#"><i class="fa-solid fa-fw fa-eye-slash"></i></a>
8
+ </span>
9
+
10
+ <span id="secret-content-template"></span>
11
+ </div>
@@ -0,0 +1,30 @@
1
+ <tr class="<%= (index % 2).zero? ? 'even' : 'odd' %> <%= row_class_mapper.call(item) %>">
2
+ <% fields.each do |field, class_mapper, label, value_mapper| %>
3
+ <td class="align-middle <%= class_mapper.call(item) %>">
4
+ <% if component.secret_field?(field) %>
5
+ <%= controller.helpers.render partial: 'active_element/components/secret/field',
6
+ locals: { secret: value_mapper.call(item), label: label } %>
7
+ <% else %>
8
+ <%= value_mapper.call(item) %>
9
+ <% end %>
10
+ </td>
11
+ <% end %>
12
+
13
+ <% if show %>
14
+ <td class="<%= "#{class_name}-show" %> action-column text-end">
15
+ <%= active_element_component.show_button(item, show, class: 'btn-sm') %>
16
+ </td>
17
+ <% end %>
18
+
19
+ <% if edit %>
20
+ <td class="<%= "#{class_name}-edit" %> action-column text-end">
21
+ <%= active_element_component.edit_button(item, show, class: 'btn-sm') %>
22
+ </td>
23
+ <% end %>
24
+
25
+ <% if destroy %>
26
+ <td class="<%= "#{class_name}-destroy" %> action-column text-end">
27
+ <%= active_element_component.destroy_button(item, destroy, class: 'btn-sm') %>
28
+ </td>
29
+ <% end %>
30
+ </tr>
@@ -0,0 +1,88 @@
1
+ <div class="container grouped-table">
2
+ <div class="row">
3
+ <div class="col-sm-2">
4
+ <% if group_title == true %>
5
+ <h4><%= i18n.label(grouping_field).pluralize %></h4>
6
+ <% elsif group_title.present? %>
7
+ <h4><%= group_title %></h4>
8
+ <% end %>
9
+
10
+ <ol class="list-group pt-2 <%= group_title.present? ? 'mt-3' : nil %> sticky-top">
11
+ <% grouped_collection.each do |group_identifier, group| %>
12
+ <li class="list-group-item d-flex justify-content-between align-items-start">
13
+
14
+ <div class="ms-2 me-auto pe-3">
15
+ <a style="font-size: 0.8rem;"
16
+ href="#<%= "#{class_name}-collection-group-#{group_identifier}" %>">
17
+ <%= i18n.label(group_identifier) %>
18
+ </a>
19
+ </div>
20
+
21
+ <a href="#<%= "#{class_name}-collection-group-#{group_identifier}" %>">
22
+ <span class="badge bg-primary rounded-pill">
23
+ <%= group.size %>
24
+ </span>
25
+ </a>
26
+
27
+ </li>
28
+ <% end %>
29
+ </ol>
30
+ </div>
31
+
32
+ <div class="col ms-3 ps-4 border-start">
33
+ <table class="table <%= class_name %>">
34
+ <thead class="sticky-top">
35
+ <tr>
36
+ <% fields.each do |field, _class_mapper, label, _value_mapper| %>
37
+ <th>
38
+ <%= label %>
39
+ </th>
40
+ <% end %>
41
+
42
+ <% if show %>
43
+ <th></th>
44
+ <% end %>
45
+
46
+ <% if edit %>
47
+ <th></th>
48
+ <% end %>
49
+
50
+ <% if destroy %>
51
+ <th></th>
52
+ <% end %>
53
+ </tr>
54
+ </thead>
55
+
56
+ <tbody>
57
+ <% grouped_collection.each do |group_identifier, group| %>
58
+
59
+ <tr>
60
+ <th class="collection-group-separator" colspan="<%= fields.size + (show ? 1 : 0) + (edit ? 1 : 0) + (destroy ? 1 : 0) %>">
61
+ <%= i18n.label(group_identifier) %>
62
+ <a name="<%= "#{class_name}-collection-group-#{group_identifier}" %>"></a>
63
+ </th>
64
+ <% fields.each do %>
65
+
66
+ <% end %>
67
+ </tr>
68
+
69
+ <% group.sort.each_with_index do |item, index| %>
70
+ <%= render partial: 'active_element/components/table/collection_row',
71
+ locals: {
72
+ component: component,
73
+ item: item,
74
+ fields: fields,
75
+ index: index,
76
+ class_name: class_name,
77
+ show: show,
78
+ edit: edit,
79
+ destroy: destroy,
80
+ row_class_mapper: row_class_mapper
81
+ } %>
82
+ <% end %>
83
+ <% end %>
84
+ </tbody>
85
+ </table>
86
+ </div>
87
+ </div>
88
+ </div>
@@ -0,0 +1,17 @@
1
+ <div class="row ms-3 pt-3 pb-3 row-cols-lg-auto">
2
+ <div class="col-auto">
3
+ <%= paginate collection %>
4
+ </div>
5
+
6
+ <div class="col-auto mt-2 pe-0">
7
+ Displaying
8
+ </div>
9
+ <div class="col-auto">
10
+ <%= select_tag 'collection-table-page-size-selector',
11
+ options_for_select(page_sizes, page_size),
12
+ class: 'form-select form-inline' %>
13
+ </div>
14
+ <div class="col-auto mt-2 ps-0">
15
+ of <%= number_to_human(collection.total_count) %> <%= 'record'.pluralize(collection.total_count) %>.
16
+ </div>
17
+ </div>
@@ -0,0 +1,49 @@
1
+ <table class="<%= class_name %> table" style="<%= style %>">
2
+ <thead>
3
+ <tr>
4
+ <% fields.each do |field, class_name, label, _mapper, options| %>
5
+ <th class="text-nowrap">
6
+ <%= label %>
7
+ <% if options[:description].present? %>
8
+ <button type="button"
9
+ style="background: none; border: none; outline: 0; position: absolute; margin-top: 0.3rem"
10
+ data-bs-toggle="popover"
11
+ data-bs-content="<%= options[:description] %>">
12
+ <i class="text-secondary fa-solid fa-circle-info"></i>
13
+ </button>
14
+ <% end %>
15
+ </th>
16
+ <% end %>
17
+
18
+ <% if show %>
19
+ <th></th>
20
+ <% end %>
21
+
22
+ <% if edit %>
23
+ <th></th>
24
+ <% end %>
25
+
26
+ <% if destroy %>
27
+ <th></th>
28
+ <% end %>
29
+ </tr>
30
+ </thead>
31
+
32
+ <tbody>
33
+ <% collection.each_with_index do |item, index| %>
34
+ <%= render partial: 'active_element/components/table/collection_row',
35
+ locals: {
36
+ component: component,
37
+ item: item,
38
+ index: index,
39
+ fields: fields,
40
+ class_name: class_name,
41
+ show: show,
42
+ edit: edit,
43
+ destroy: destroy,
44
+ row_class_mapper: row_class_mapper
45
+ } %>
46
+ <% end %>
47
+ </tbody>
48
+ </table>
49
+
@@ -0,0 +1,39 @@
1
+ <% if new %>
2
+ <%= active_element_component.new_button(collection, float: 'end', class: 'mb-3') %>
3
+ <% end %>
4
+
5
+ <% if display_pagination %>
6
+ <%=
7
+ render partial: 'active_element/components/table/pagination',
8
+ locals: { collection: collection, params: params, page_size: page_size, page_sizes: page_sizes }
9
+ %>
10
+ <% end %>
11
+
12
+ <% if group %>
13
+ <%= render partial: 'active_element/components/table/grouped_collection',
14
+ locals: { component: component,
15
+ collection: collection,
16
+ fields: fields,
17
+ grouped_collection: component.grouped_collection,
18
+ grouping_field: group,
19
+ group_title: group_title,
20
+ show: show,
21
+ edit: edit,
22
+ destroy: destroy,
23
+ class_name: class_name,
24
+ style: style,
25
+ i18n: i18n,
26
+ row_class_mapper: row_class_mapper } %>
27
+ <% else %>
28
+ <%= render partial: 'active_element/components/table/ungrouped_collection',
29
+ locals: { component: component,
30
+ collection: collection,
31
+ fields: fields,
32
+ show: show,
33
+ edit: edit,
34
+ destroy: destroy,
35
+ class_name: class_name,
36
+ style: style,
37
+ i18n: i18n,
38
+ row_class_mapper: row_class_mapper } %>
39
+ <% end %>
@@ -0,0 +1,39 @@
1
+ <% if destroy && item.present? %>
2
+ <%= active_element_component.destroy_button(item, destroy, float: 'end') %>
3
+ <% end %>
4
+
5
+ <% if edit && item.present? %>
6
+ <%= active_element_component.edit_button(item, edit, float: 'end') %>
7
+ <% end %>
8
+
9
+ <% if new %>
10
+ <%= active_element_component.new_button(item, float: 'end', class: 'mb-3') %>
11
+ <% end %>
12
+
13
+ <table class="<%= class_name %> table" style="<%= style %>">
14
+ <tbody>
15
+ <% fields.each do |field, class_mapper, label, value_mapper, options| %>
16
+ <tr>
17
+ <th>
18
+ <%= label %>
19
+ <% if options[:description].present? %>
20
+ <button type="button"
21
+ style="background: none; border: none; outline: 0; position: absolute; margin-top: 0.3rem"
22
+ data-bs-toggle="popover"
23
+ data-bs-content="<%= options[:description] %>">
24
+ <i class="text-secondary fa-solid fa-circle-info"></i>
25
+ </button>
26
+ <% end %>
27
+ </th>
28
+ <td class="<%= class_mapper.call(item) %>">
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 } %>
32
+ <% else %>
33
+ <%= value_mapper.call(item) %>
34
+ <% end %>
35
+ </td>
36
+ </tr>
37
+ <% end %>
38
+ </tbody>
39
+ </table>
@@ -0,0 +1,7 @@
1
+ <div class="p-3">
2
+ <% if tabs.size > 10 %>
3
+ <%= controller.helpers.render partial: 'active_element/components/vertical_tabs', locals: { tabs: tabs, class_name: class_name } %>
4
+ <% else %>
5
+ <%= controller.helpers.render partial: 'active_element/components/horizontal_tabs', locals: { tabs: tabs, class_name: class_name } %>
6
+ <% end %>
7
+ </div>
@@ -0,0 +1,5 @@
1
+ <% if value %>
2
+ <i class="text-success fa-regular fa-fw fa-circle-check align-center align-middle"></i>
3
+ <% else %>
4
+ <i class="text-danger fa-regular fa-fw fa-circle-xmark align-center align-middle"></i>
5
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <% if value.present? %>
2
+ <%= value.strftime('%F') %>
3
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <% if value.present? %>
2
+ <%= value.strftime('%c') %>
3
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <% if value.present? %>
2
+ <%= value.strftime('%T') %>
3
+ <% end %>
@@ -0,0 +1,33 @@
1
+ <h1>Forbidden</h1>
2
+
3
+ <h2>You do not have access to this page</h2>
4
+
5
+ <hr/>
6
+
7
+ <% if missing_permissions.present? %>
8
+ <p>Your user account requires the following permission(s) to view this content:</p>
9
+
10
+ <div>
11
+ <ul style="list-style-type: none;">
12
+ <% missing_permissions.each do |missing_permission| %>
13
+ <li class="font-monospace"><%= missing_permission %></li>
14
+ <% end %>
15
+ </ul>
16
+ </div>
17
+
18
+ <hr/>
19
+ <% end %>
20
+
21
+ <p>Please contact your administrator if you need access to this page, or <%= link_to 'go back', request.referrer %> to the previous page and try a different option.</p>
22
+
23
+ <% if alternatives.present? %>
24
+ <div class="alternative-links">
25
+ <h5>Alternatively, try one of the following suggestions:</h5>
26
+
27
+ <ul class="pt-1" style="list-style-type: none">
28
+ <% alternatives.first(5).each do |route| %>
29
+ <li class="mt-1 font-monospace"><%= link_to route.title, route.path %></li>
30
+ <% end %>
31
+ </ul>
32
+ </div>
33
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if item.separator? %>
2
+ <li>
3
+ <div class="menu-item-separator">
4
+ <div class="menu-item-separator-line"></div>
5
+ </div>
6
+ </li>
7
+ <% else %>
8
+ <li><%= link_to item.name, item.url, class: 'menu-section-dropdown-item dropdown-item' %></li>
9
+ <% end %>
@@ -0,0 +1,30 @@
1
+ <div class="application-menu sticky-top 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(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: 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>
@@ -0,0 +1 @@
1
+ <div id="theme-select"></div>
@@ -0,0 +1,6 @@
1
+ <div id="theme-templates" class="d-none">
2
+ <div id="theme-select-buttons">
3
+ <a id="theme-dark-button-template" href="#" class="dark-theme" data-theme-switch-to="light"><i class="fa-regular fa-fw fa-moon"></i></a>
4
+ <a id="theme-light-button-template" href="#" class="light-theme" data-theme-switch-to="dark"><i class="fa-regular fa-fw fa-sun"></i></a>
5
+ </div>
6
+ </div>
@@ -0,0 +1,3 @@
1
+ <li class="page-item">
2
+ <%= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link' %>
3
+ </li>
@@ -0,0 +1,3 @@
1
+ <li class='page-item disabled'>
2
+ <%= link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link' %>
3
+ </li>