goodmin 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +1359 -0
  4. data/Rakefile +56 -0
  5. data/app/assets/stylesheets/goodmin/application.css +75 -0
  6. data/app/controllers/goodmin/application_controller.rb +43 -0
  7. data/app/controllers/goodmin/resource_controller.rb +235 -0
  8. data/app/helpers/goodmin/application_helper.rb +45 -0
  9. data/app/javascript/goodmin/application.js +8 -0
  10. data/app/javascript/goodmin/controllers/batch_actions_controller.js +101 -0
  11. data/app/javascript/goodmin/controllers/datetimepicker_controller.js +24 -0
  12. data/app/javascript/goodmin/controllers/navigation_controller.js +30 -0
  13. data/app/jobs/goodmin/application_job.rb +4 -0
  14. data/app/mailers/goodmin/application_mailer.rb +6 -0
  15. data/app/models/goodmin/application_record.rb +5 -0
  16. data/app/views/goodmin/application/welcome.html.erb +17 -0
  17. data/app/views/goodmin/fields/association/_form.html.erb +19 -0
  18. data/app/views/goodmin/fields/association/_index.html.erb +6 -0
  19. data/app/views/goodmin/fields/association/_show.html.erb +6 -0
  20. data/app/views/goodmin/fields/boolean/_form.html.erb +7 -0
  21. data/app/views/goodmin/fields/boolean/_index.html.erb +1 -0
  22. data/app/views/goodmin/fields/boolean/_show.html.erb +1 -0
  23. data/app/views/goodmin/fields/date/_form.html.erb +6 -0
  24. data/app/views/goodmin/fields/date/_index.html.erb +1 -0
  25. data/app/views/goodmin/fields/date/_show.html.erb +1 -0
  26. data/app/views/goodmin/fields/date_time/_form.html.erb +6 -0
  27. data/app/views/goodmin/fields/date_time/_index.html.erb +1 -0
  28. data/app/views/goodmin/fields/date_time/_show.html.erb +1 -0
  29. data/app/views/goodmin/fields/enum/_index.html.erb +1 -0
  30. data/app/views/goodmin/fields/enum/_show.html.erb +1 -0
  31. data/app/views/goodmin/fields/nested_has_one/_form.html.erb +6 -0
  32. data/app/views/goodmin/fields/nested_has_one/_index.html.erb +1 -0
  33. data/app/views/goodmin/fields/nested_has_one/_show.html.erb +1 -0
  34. data/app/views/goodmin/fields/number/_form.html.erb +5 -0
  35. data/app/views/goodmin/fields/number/_index.html.erb +1 -0
  36. data/app/views/goodmin/fields/number/_show.html.erb +1 -0
  37. data/app/views/goodmin/fields/password/_form.html.erb +5 -0
  38. data/app/views/goodmin/fields/password/_index.html.erb +1 -0
  39. data/app/views/goodmin/fields/password/_show.html.erb +1 -0
  40. data/app/views/goodmin/fields/select/_form.html.erb +5 -0
  41. data/app/views/goodmin/fields/select/_index.html.erb +1 -0
  42. data/app/views/goodmin/fields/select/_show.html.erb +1 -0
  43. data/app/views/goodmin/fields/string/_form.html.erb +5 -0
  44. data/app/views/goodmin/fields/string/_index.html.erb +1 -0
  45. data/app/views/goodmin/fields/string/_show.html.erb +1 -0
  46. data/app/views/goodmin/fields/text/_form.html.erb +5 -0
  47. data/app/views/goodmin/fields/text/_index.html.erb +1 -0
  48. data/app/views/goodmin/fields/text/_show.html.erb +1 -0
  49. data/app/views/goodmin/resource/_actions.html.erb +9 -0
  50. data/app/views/goodmin/resource/_batch_actions.html.erb +12 -0
  51. data/app/views/goodmin/resource/_breadcrumb.html.erb +33 -0
  52. data/app/views/goodmin/resource/_breadcrumb_actions.html.erb +41 -0
  53. data/app/views/goodmin/resource/_button_actions.html.erb +3 -0
  54. data/app/views/goodmin/resource/_errors.html.erb +9 -0
  55. data/app/views/goodmin/resource/_export_actions.html.erb +15 -0
  56. data/app/views/goodmin/resource/_filters.html.erb +22 -0
  57. data/app/views/goodmin/resource/_form.html.erb +26 -0
  58. data/app/views/goodmin/resource/_pagination.html.erb +40 -0
  59. data/app/views/goodmin/resource/_scopes.html.erb +14 -0
  60. data/app/views/goodmin/resource/_table.html.erb +45 -0
  61. data/app/views/goodmin/resource/columns/_actions.html.erb +28 -0
  62. data/app/views/goodmin/resource/edit.html.erb +5 -0
  63. data/app/views/goodmin/resource/index.csv.csvbuilder +5 -0
  64. data/app/views/goodmin/resource/index.html.erb +10 -0
  65. data/app/views/goodmin/resource/index.json.jbuilder +3 -0
  66. data/app/views/goodmin/resource/new.html.erb +5 -0
  67. data/app/views/goodmin/resource/show.html.erb +11 -0
  68. data/app/views/goodmin/resource/show.json.jbuilder +1 -0
  69. data/app/views/goodmin/sessions/new.html.erb +11 -0
  70. data/app/views/goodmin/shared/_navigation.html.erb +0 -0
  71. data/app/views/goodmin/shared/_navigation_aside.html.erb +7 -0
  72. data/app/views/layouts/goodmin/_content.html.erb +13 -0
  73. data/app/views/layouts/goodmin/_layout.html.erb +22 -0
  74. data/app/views/layouts/goodmin/application.html.erb +28 -0
  75. data/app/views/layouts/goodmin/login.html.erb +18 -0
  76. data/config/importmap.rb +5 -0
  77. data/config/locales/en.yml +49 -0
  78. data/config/locales/pl-BR.yml +49 -0
  79. data/config/locales/pt-BR.yml +49 -0
  80. data/config/locales/sv.yml +49 -0
  81. data/config/routes.rb +3 -0
  82. data/lib/generators/goodmin/authentication/authentication_generator.rb +41 -0
  83. data/lib/generators/goodmin/authentication/templates/sessions_controller.rb +9 -0
  84. data/lib/generators/goodmin/install/install_generator.rb +41 -0
  85. data/lib/generators/goodmin/policy/policy_generator.rb +7 -0
  86. data/lib/generators/goodmin/policy/templates/policy.rb +23 -0
  87. data/lib/generators/goodmin/resource/resource_generator.rb +31 -0
  88. data/lib/generators/goodmin/resource/templates/resource.rb +25 -0
  89. data/lib/generators/goodmin/resource/templates/resource_controller.rb +9 -0
  90. data/lib/generators/goodmin/resource/templates/resource_model.rb +4 -0
  91. data/lib/generators/goodmin/resource/templates/resource_service.rb +23 -0
  92. data/lib/goodmin/authentication/sessions_controller.rb +46 -0
  93. data/lib/goodmin/authentication/user.rb +27 -0
  94. data/lib/goodmin/authentication.rb +35 -0
  95. data/lib/goodmin/authorization/policy.rb +41 -0
  96. data/lib/goodmin/authorization.rb +69 -0
  97. data/lib/goodmin/engine.rb +30 -0
  98. data/lib/goodmin/fields/association.rb +62 -0
  99. data/lib/goodmin/fields/base.rb +57 -0
  100. data/lib/goodmin/fields/boolean.rb +6 -0
  101. data/lib/goodmin/fields/date.rb +6 -0
  102. data/lib/goodmin/fields/date_time.rb +6 -0
  103. data/lib/goodmin/fields/enum.rb +15 -0
  104. data/lib/goodmin/fields/nested_has_one.rb +41 -0
  105. data/lib/goodmin/fields/number.rb +6 -0
  106. data/lib/goodmin/fields/password.rb +6 -0
  107. data/lib/goodmin/fields/select.rb +19 -0
  108. data/lib/goodmin/fields/string.rb +6 -0
  109. data/lib/goodmin/fields/text.rb +6 -0
  110. data/lib/goodmin/generators/base.rb +49 -0
  111. data/lib/goodmin/generators/named_base.rb +31 -0
  112. data/lib/goodmin/helpers/application.rb +47 -0
  113. data/lib/goodmin/helpers/batch_actions.rb +21 -0
  114. data/lib/goodmin/helpers/filters.rb +123 -0
  115. data/lib/goodmin/helpers/forms.rb +42 -0
  116. data/lib/goodmin/helpers/navigation.rb +52 -0
  117. data/lib/goodmin/helpers/tables.rb +25 -0
  118. data/lib/goodmin/helpers/translations.rb +19 -0
  119. data/lib/goodmin/paginator.rb +55 -0
  120. data/lib/goodmin/resolver.rb +141 -0
  121. data/lib/goodmin/resources/attribute.rb +46 -0
  122. data/lib/goodmin/resources/form_builder.rb +96 -0
  123. data/lib/goodmin/resources/form_component.rb +65 -0
  124. data/lib/goodmin/resources/form_components/col.rb +33 -0
  125. data/lib/goodmin/resources/form_components/row.rb +25 -0
  126. data/lib/goodmin/resources/form_components/section.rb +51 -0
  127. data/lib/goodmin/resources/form_components/tab.rb +49 -0
  128. data/lib/goodmin/resources/resource/associations.rb +23 -0
  129. data/lib/goodmin/resources/resource/batch_actions.rb +56 -0
  130. data/lib/goodmin/resources/resource/filters.rb +44 -0
  131. data/lib/goodmin/resources/resource/ordering.rb +41 -0
  132. data/lib/goodmin/resources/resource/pagination.rb +22 -0
  133. data/lib/goodmin/resources/resource/scopes.rb +61 -0
  134. data/lib/goodmin/resources/resource.rb +199 -0
  135. data/lib/goodmin/resources/resource_controller/batch_actions.rb +49 -0
  136. data/lib/goodmin/resources/resource_service/associations.rb +23 -0
  137. data/lib/goodmin/resources/resource_service/batch_actions.rb +52 -0
  138. data/lib/goodmin/resources/resource_service/filters.rb +44 -0
  139. data/lib/goodmin/resources/resource_service/ordering.rb +41 -0
  140. data/lib/goodmin/resources/resource_service/pagination.rb +22 -0
  141. data/lib/goodmin/resources/resource_service/scopes.rb +61 -0
  142. data/lib/goodmin/resources/resource_service.rb +199 -0
  143. data/lib/goodmin/service_locator.rb +25 -0
  144. data/lib/goodmin/version.rb +3 -0
  145. data/lib/goodmin.rb +44 -0
  146. data/lib/tasks/goodmin_tasks.rake +4 -0
  147. metadata +461 -0
@@ -0,0 +1,7 @@
1
+ <div class="form-group">
2
+ <div class="form-check">
3
+ <%= f.check_box field.attribute, class: "form-check-input" %>
4
+ <%= f.label field.attribute, class: "form-check-label" %>
5
+ </div>
6
+ <%= content_tag(:p, field.hint, class: "help-block") if field.hint.present? %>
7
+ </div>
@@ -0,0 +1 @@
1
+ <%= t(field.value.to_s) %>
@@ -0,0 +1 @@
1
+ <%= t(field.value.to_s) %>
@@ -0,0 +1,6 @@
1
+ <% value = field.value.try(:strftime, translate_scoped("datetimepickers.datepicker")) %>
2
+ <div class="form-group">
3
+ <%= f.label field.attribute %>
4
+ <%= f.text_field field.attribute, class: "form-control", value: value, data: { behavior: "datepicker" } %>
5
+ <%= content_tag(:p, field.hint, class: "help-block") if field.hint.present? %>
6
+ </div>
@@ -0,0 +1 @@
1
+ <%= l(field.value, format: :long) if field.value %>
@@ -0,0 +1 @@
1
+ <%= l(field.value, format: :long) if field.value %>
@@ -0,0 +1,6 @@
1
+ <% value = field.value.try(:strftime, translate_scoped("datetimepickers.datetimepicker")) %>
2
+ <div class="form-group">
3
+ <%= f.label field.attribute %>
4
+ <%= f.text_field field.attribute, class: "form-control", value: value, data: { behavior: "datetimepicker" } %>
5
+ <%= content_tag(:p, field.hint, class: "help-block") if field.hint.present? %>
6
+ </div>
@@ -0,0 +1 @@
1
+ <%= l(field.value, format: :long) if field.value %>
@@ -0,0 +1 @@
1
+ <%= l(field.value, format: :long) if field.value %>
@@ -0,0 +1 @@
1
+ <%= field.value&.humanize %>
@@ -0,0 +1 @@
1
+ <%= field.value&.humanize %>
@@ -0,0 +1,6 @@
1
+ <%= f.fields_for field.attribute, field.associated_record do |nested_f| %>
2
+ <fieldset>
3
+ <legend><%= field.attribute.to_s.humanize %></legend>
4
+ <%= render_form_nodes_for(field.nested_form_nodes, nested_f, record: field.associated_record, resource_service: field.associated_service) %>
5
+ </fieldset>
6
+ <% end %>
@@ -0,0 +1 @@
1
+ <%= field.value %>
@@ -0,0 +1 @@
1
+ <%= field.value %>
@@ -0,0 +1,5 @@
1
+ <div class="form-group">
2
+ <%= f.label field.attribute %>
3
+ <%= f.number_field field.attribute, class: "form-control" %>
4
+ <%= content_tag(:p, field.hint, class: "help-block") if field.hint.present? %>
5
+ </div>
@@ -0,0 +1 @@
1
+ <%= field.value %>
@@ -0,0 +1 @@
1
+ <%= field.value %>
@@ -0,0 +1,5 @@
1
+ <div class="form-group">
2
+ <%= f.label field.attribute %>
3
+ <%= f.password_field field.attribute, class: "form-control" %>
4
+ <%= content_tag(:p, field.hint, class: "help-block") if field.hint.present? %>
5
+ </div>
@@ -0,0 +1 @@
1
+ <%= "•" * 8 if field.value.present? %>
@@ -0,0 +1 @@
1
+ <%= "•" * 8 if field.value.present? %>
@@ -0,0 +1,5 @@
1
+ <div class="form-group">
2
+ <%= f.label field.attribute %>
3
+ <%= f.select field.attribute, field.collection, field.select_options, field.select_html_options %>
4
+ <%= content_tag(:p, field.hint, class: "help-block") if field.hint.present? %>
5
+ </div>
@@ -0,0 +1 @@
1
+ <%= field.value %>
@@ -0,0 +1 @@
1
+ <%= field.value %>
@@ -0,0 +1,5 @@
1
+ <div class="form-group">
2
+ <%= f.label field.attribute %>
3
+ <%= f.text_field field.attribute, class: "form-control" %>
4
+ <%= content_tag(:p, field.hint, class: "help-block") if field.hint.present? %>
5
+ </div>
@@ -0,0 +1 @@
1
+ <%= field.value %>
@@ -0,0 +1 @@
1
+ <%= field.value %>
@@ -0,0 +1,5 @@
1
+ <div class="form-group">
2
+ <%= f.label field.attribute %>
3
+ <%= f.text_area field.attribute, class: "form-control" %>
4
+ <%= content_tag(:p, field.hint, class: "help-block") if field.hint.present? %>
5
+ </div>
@@ -0,0 +1 @@
1
+ <%= field.value %>
@@ -0,0 +1 @@
1
+ <%= field.value %>
@@ -0,0 +1,9 @@
1
+ <div id="actions">
2
+ <div class="pull-left">
3
+ <%= render partial: "batch_actions" %>
4
+ </div>
5
+ <div class="pull-right">
6
+ <%= render partial: "button_actions" %>
7
+ <%= render partial: "export_actions" %>
8
+ </div>
9
+ </div>
@@ -0,0 +1,12 @@
1
+ <% if @resource_service.include_batch_actions? %>
2
+ <%= link_to translate_scoped("batch_actions.buttons.select_all"), "#", class: "btn btn-default",
3
+ data: { batch_actions_target: "selectAll", action: "click->batch-actions#toggle" } %>
4
+ <%= link_to translate_scoped("batch_actions.buttons.deselect_all"), "#", class: "btn btn-default hidden",
5
+ data: { batch_actions_target: "selectNone", action: "click->batch-actions#toggle" } %>
6
+
7
+ <div class="btn-group">
8
+ <% @resource_service.batch_action_map.each do |name, options| %>
9
+ <%= batch_action_link(name, options) %>
10
+ <% end %>
11
+ </div>
12
+ <% end %>
@@ -0,0 +1,33 @@
1
+ <div id="breadcrumb">
2
+ <ol class="breadcrumb">
3
+ <% if @resource_parents %>
4
+ <% @resource_parents.each do |parent| %>
5
+ <li>
6
+ <%= link_to parent.class.model_name.human(count: 2), parent.class %>
7
+ </li>
8
+ <li>
9
+ <%= link_to resource_display_name(parent), parent %>
10
+ </li>
11
+ <% end %>
12
+ <% end %>
13
+ <% if action_name == "index" %>
14
+ <li class="active">
15
+ <%= @resource_class.model_name.human(count: 2) %>
16
+ </li>
17
+ <% else %>
18
+ <li>
19
+ <%= link_to @resource_class.model_name.human(count: 2), [*@resource_parents, @resource_class] %>
20
+ </li>
21
+ <li class="active">
22
+ <% if @resource.new_record? %>
23
+ <%= t("helpers.submit.create", model: @resource_class.model_name.human) %>
24
+ <% else %>
25
+ <%= @resource_service.display_name(@resource) %>
26
+ <% end %>
27
+ </li>
28
+ <% if @resource.persisted? %>
29
+ <%= render partial: "breadcrumb_actions" %>
30
+ <% end %>
31
+ <% end %>
32
+ </ol>
33
+ </div>
@@ -0,0 +1,41 @@
1
+ <li class="dropdown pull-right">
2
+ <a href="#" data-toggle="dropdown">
3
+ <%= translate_scoped("actions.label") %> <span class="caret"></span>
4
+ </a>
5
+ <ul class="dropdown-menu">
6
+ <% if policy(@resource).show? && action_name != "show" %>
7
+ <li>
8
+ <%= link_to translate_scoped("actions.show"), [*@resource_parents, @resource] %>
9
+ </li>
10
+ <% end %>
11
+ <% if policy(@resource).edit? && action_name != "edit" %>
12
+ <li>
13
+ <%= link_to translate_scoped("actions.edit"), [:edit, *@resource_parents, @resource] %>
14
+ </li>
15
+ <% end %>
16
+ <% if policy(@resource).destroy? %>
17
+ <li>
18
+ <%= link_to translate_scoped("actions.destroy"), [*@resource_parents, @resource], method: :delete,
19
+ data: { confirm: translate_scoped("actions.confirm_message") } %>
20
+ </li>
21
+ <% end %>
22
+ </ul>
23
+ </li>
24
+
25
+ <% if @resource_service.has_many_map.present? %>
26
+ <li class="dropdown pull-right">
27
+ <a href="#" data-toggle="dropdown">
28
+ <%= translate_scoped("associations.label") %> <span class="caret"></span>
29
+ </a>
30
+ <ul class="dropdown-menu">
31
+ <% @resource_service.has_many_map.each do |name, options| %>
32
+ <% if policy(options[:class_name].constantize).index? %>
33
+ <li>
34
+ <%= link_to(options[:class_name].constantize.model_name.human(count: 2),
35
+ send("#{@resource_class.name.underscore}_#{name}_path", @resource)) %>
36
+ </li>
37
+ <% end %>
38
+ <% end %>
39
+ </ul>
40
+ </li>
41
+ <% end %>
@@ -0,0 +1,3 @@
1
+ <% if policy(@resource_service.build_resource({})).new? %>
2
+ <%= link_to t("helpers.submit.create", model: @resource_class.model_name.human), [:new, *@resource_parents, @resource_class.model_name.singular_route_key.to_sym], class: "btn btn-default" %>
3
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if errors.present? %>
2
+ <div class="alert alert-danger">
3
+ <ul class="list-unstyled">
4
+ <% errors.full_messages.each do |error| %>
5
+ <li><%= error %></li>
6
+ <% end %>
7
+ </ul>
8
+ </div>
9
+ <% end %>
@@ -0,0 +1,15 @@
1
+ <% if @resource_service.attrs_for_export.present? %>
2
+ <div class="btn-group">
3
+ <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4
+ <%= translate_scoped("actions.export") %> <span class="caret"></span>
5
+ </button>
6
+ <ul class="dropdown-menu" role="menu">
7
+ <li>
8
+ <%= link_to "#{translate_scoped("actions.export_as")} JSON", url_for(params.to_unsafe_h.merge(only_path: true, format: "json")) %>
9
+ </li>
10
+ <li>
11
+ <%= link_to "#{translate_scoped("actions.export_as")} CSV", url_for(params.to_unsafe_h.merge(only_path: true, format: "csv")) %>
12
+ </li>
13
+ </ul>
14
+ </div>
15
+ <% end %>
@@ -0,0 +1,22 @@
1
+ <% if @resource_service.filter_map.present? %>
2
+ <div id="filters" class="panel panel-default">
3
+ <div class="panel-body">
4
+ <%= filter_form do |f| %>
5
+ <%= hidden_field_tag :scope, params[:scope] %>
6
+ <%= hidden_field_tag :order, params[:order] %>
7
+
8
+ <% @resource_service.filter_map.each do |name, options| %>
9
+ <%= partial_override "#{controller_path}/filters/#{name}", f: f, name: name, options: options do %>
10
+ <%= f.filter_field(name, options) %>
11
+ <% end %>
12
+ <% end %>
13
+
14
+ <div class="form-group pull-right">
15
+ <label class="control-label">&nbsp;</label><br>
16
+ <%= f.apply_filters_button %>
17
+ <%= f.clear_filters_button %>
18
+ </div>
19
+ <% end %>
20
+ </div>
21
+ </div>
22
+ <% end %>
@@ -0,0 +1,26 @@
1
+ <% form_tabs = @resource_service.form_tabs %>
2
+ <% if form_tabs.any? %>
3
+ <% active_tab = form_tabs.find { |t| t.key == params[:tab] } || form_tabs.first %>
4
+ <div class="row">
5
+ <div class="col-md-2">
6
+ <ul class="nav nav-pills nav-stacked">
7
+ <% form_tabs.each do |tab| %>
8
+ <li class="<%= "active" if tab == active_tab %>">
9
+ <%= link_to tab.title, request.path + "?tab=#{CGI.escape(tab.key)}" %>
10
+ </li>
11
+ <% end %>
12
+ </ul>
13
+ </div>
14
+ <div class="col-md-10">
15
+ <%= form_for @resource do |f| %>
16
+ <%= render_form_nodes(active_tab.children, f) %>
17
+ <%= f.submit class: "btn btn-primary" %>
18
+ <% end %>
19
+ </div>
20
+ </div>
21
+ <% else %>
22
+ <%= form_for @resource do |f| %>
23
+ <%= render_form_nodes(@resource_service.form_nodes, f) %>
24
+ <%= f.submit class: "btn btn-primary" %>
25
+ <% end %>
26
+ <% end %>
@@ -0,0 +1,40 @@
1
+ <div class="pull-left">
2
+ <% if @resource_service.paginator.total_pages > 1 %>
3
+ <nav>
4
+ <ul class="pagination">
5
+ <% unless @resource_service.paginator.pages.first == 1 && @resource_service.paginator.current_page == @resource_service.paginator.pages.first %>
6
+ <li><%= link_to translate_scoped("pagination.first"), params.to_unsafe_h.merge(page: 1) %></li>
7
+ <li><%= link_to "«", params.to_unsafe_h.merge(page: @resource_service.paginator.current_page - 1) %></li>
8
+ <% end %>
9
+ <% unless @resource_service.paginator.pages.first == 1 %>
10
+ <li class="disabled"><%= link_to "…" %></li>
11
+ <% end %>
12
+ <% @resource_service.paginator.pages.each do |page| %>
13
+ <li class="<%= "active" if page == @resource_service.paginator.current_page %>">
14
+ <%= link_to page, params.to_unsafe_h.merge(page: page) %>
15
+ </li>
16
+ <% end %>
17
+ <% unless @resource_service.paginator.pages.last == @resource_service.paginator.total_pages %>
18
+ <li class="disabled"><%= link_to "…" %></li>
19
+ <% end %>
20
+ <% unless @resource_service.paginator.pages.last == @resource_service.paginator.total_pages && @resource_service.paginator.current_page == @resource_service.paginator.pages.last %>
21
+ <li><%= link_to "»", params.to_unsafe_h.merge(page: @resource_service.paginator.current_page + 1) %></li>
22
+ <li><%= link_to translate_scoped("pagination.last"), params.to_unsafe_h.merge(page: @resource_service.paginator.total_pages) %></li>
23
+ <% end %>
24
+ </ul>
25
+ </nav>
26
+ <% end %>
27
+ </div>
28
+ <div class="pagination-entries pull-right hidden-xs">
29
+ <% if @resources.length == 0 %>
30
+ <%= translate_scoped("pagination.entries.zero",
31
+ resource: @resource_class.model_name.human(count: @resources.length).downcase
32
+ ) %>
33
+ <% else %>
34
+ <%= translate_scoped("pagination.entries.other",
35
+ resource: @resource_class.model_name.human(count: @resources.length).downcase,
36
+ count: @resources.length,
37
+ total: @resource_service.paginator.total_resources
38
+ ) %>
39
+ <% end %>
40
+ </div>
@@ -0,0 +1,14 @@
1
+ <% unless @resource_service.scope_map.empty? %>
2
+ <div id="scopes">
3
+ <ul class="nav nav-tabs">
4
+ <% @resource_service.scope_map.each do |name, options| %>
5
+ <li class="<%= "active" if @resource_service.scoped_by?(name) %>">
6
+ <%= link_to url_for(params.to_unsafe_h.merge(scope: name, only_path: true).except(:page)) do %>
7
+ <%= translate_scoped("scopes.labels.#{name.to_s.underscore}", default: name.to_s.titleize) %>
8
+ <span class="text-muted"> (<%= @resource_service.scope_count(name) %>)</span>
9
+ <% end %>
10
+ </li>
11
+ <% end %>
12
+ </ul>
13
+ </div>
14
+ <% end %>
@@ -0,0 +1,45 @@
1
+ <div id="table" class="table-responsive">
2
+ <table class="table table-bordered table-hover">
3
+ <caption class="hide">
4
+ <%= @resource_class.model_name.human(count: 2) %>
5
+ </caption>
6
+ <thead>
7
+ <tr>
8
+ <% if @resource_service.include_batch_actions? %>
9
+ <th></th>
10
+ <% end %>
11
+ <% @resource_service.attrs_for_index.each do |attribute| %>
12
+ <th class="column-<%= attribute.name %>">
13
+ <%= column_header attribute %>
14
+ </th>
15
+ <% end %>
16
+ <th></th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <% @resources.each do |resource| %>
21
+ <tr data-resource-id="<%= resource.id %>" class="<%= "highlight" if flash[:updated_ids] && flash[:updated_ids].include?(resource.id) %>">
22
+ <% if @resource_service.include_batch_actions? %>
23
+ <td align="center"
24
+ data-batch-actions-target="checkboxContainer"
25
+ data-action="click->batch-actions#containerClick">
26
+ <%= check_box_tag "batch_action[items][#{resource.id}]", nil, nil,
27
+ data: { batch_actions_target: "checkbox", action: "change->batch-actions#checkboxChange" } %>
28
+ </td>
29
+ <% end %>
30
+ <% @resource_service.attrs_for_index.each do |attribute| %>
31
+ <td>
32
+ <% field = attribute.to_field(record: resource, resource_service: @resource_service) %>
33
+ <%= partial_override "#{controller_path}/columns/#{attribute.name}", resource: resource do %>
34
+ <%= render partial: field.class.partial_index, locals: { field: field } %>
35
+ <% end %>
36
+ </td>
37
+ <% end %>
38
+ <td>
39
+ <%= render partial: "#{controller_path}/columns/actions", locals: { resource: resource } %>
40
+ </td>
41
+ </tr>
42
+ <% end %>
43
+ </tbody>
44
+ </table>
45
+ </div>
@@ -0,0 +1,28 @@
1
+ <div class="btn-group btn-group-sm pull-right">
2
+ <% if policy(resource).show? %>
3
+ <%= link_to(
4
+ translate_scoped("actions.show"),
5
+ [*@resource_parents, resource],
6
+ class: "btn btn-default",
7
+ title: translate_scoped("actions.show_title", resource: resource)
8
+ ) %>
9
+ <% end %>
10
+ <% if policy(resource).edit? %>
11
+ <%= link_to(
12
+ translate_scoped("actions.edit"),
13
+ [:edit, *@resource_parents, resource],
14
+ class: "btn btn-default",
15
+ title: translate_scoped("actions.edit_title", resource: resource)
16
+ ) %>
17
+ <% end %>
18
+ <% if policy(resource).destroy? %>
19
+ <%= link_to(
20
+ translate_scoped("actions.destroy"),
21
+ [*@resource_parents, resource],
22
+ method: :delete,
23
+ class: "btn btn-default",
24
+ title: translate_scoped("actions.destroy_title", resource: resource),
25
+ data: { confirm: translate_scoped("actions.confirm_message") }
26
+ ) %>
27
+ <% end %>
28
+ </div>
@@ -0,0 +1,5 @@
1
+ <%= render partial: "breadcrumb" %>
2
+
3
+ <%= render partial: "errors", locals: { errors: @resource.errors } %>
4
+
5
+ <%= render partial: "form" %>
@@ -0,0 +1,5 @@
1
+ csv << @resource_service.attrs_for_export.map(&:name)
2
+
3
+ @resources.limit(nil).offset(nil).each do |resource|
4
+ csv << @resource_service.attrs_for_export.map { |attr| resource.send(attr.name) }
5
+ end
@@ -0,0 +1,10 @@
1
+ <%= render partial: "breadcrumb" %>
2
+ <%= render partial: "scopes" %>
3
+ <%= render partial: "filters" %>
4
+
5
+ <div data-controller="batch-actions">
6
+ <%= render partial: "actions" %>
7
+ <%= render partial: "table" %>
8
+ </div>
9
+
10
+ <%= render partial: "pagination" %>
@@ -0,0 +1,3 @@
1
+ json.array! @resources.limit(nil).offset(nil) do |resource|
2
+ json.extract! resource, *@resource_service.attrs_for_export.map(&:name)
3
+ end
@@ -0,0 +1,5 @@
1
+ <%= render partial: "breadcrumb" %>
2
+
3
+ <%= render partial: "errors", locals: { errors: @resource.errors } %>
4
+
5
+ <%= render partial: "form" %>
@@ -0,0 +1,11 @@
1
+ <%= render partial: "breadcrumb" %>
2
+
3
+ <table class="table">
4
+ <% @resource_service.attrs_for_show.each do |attribute| %>
5
+ <% field = attribute.to_field(record: @resource, resource_service: @resource_service) %>
6
+ <tr>
7
+ <th><%= @resource_class.human_attribute_name(attribute.name) %></th>
8
+ <td><%= render partial: field.class.partial_show, locals: { field: field } %></td>
9
+ </tr>
10
+ <% end %>
11
+ </table>
@@ -0,0 +1 @@
1
+ json.extract! @resource, *@resource_service.attrs_for_export.map(&:name)
@@ -0,0 +1,11 @@
1
+ <%= form_for(@admin_user, url: session_path) do |f| %>
2
+ <div class="form-group">
3
+ <%= f.label @admin_user.class.login_column %>
4
+ <%= f.text_field @admin_user.class.login_column, class: "form-control" %>
5
+ </div>
6
+ <div class="form-group">
7
+ <%= f.label :password %>
8
+ <%= f.password_field :password, class: "form-control" %>
9
+ </div>
10
+ <%= f.submit translate_scoped("sessions.sign_in"), class: "btn btn-block btn-primary" %>
11
+ <% end %>
File without changes
@@ -0,0 +1,7 @@
1
+ <% if authentication_enabled? &&
2
+ admin_user.singleton_class.include?(Goodmin::Authentication::User) &&
3
+ admin_user_signed_in? %>
4
+ <li>
5
+ <%= link_to translate_scoped("sessions.sign_out"), session_path, method: :delete %>
6
+ </li>
7
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <% if flash[:alert] %>
2
+ <div class="alert alert-danger">
3
+ <%= flash[:alert] %>
4
+ </div>
5
+ <% end %>
6
+
7
+ <% if flash[:notice] %>
8
+ <div class="alert alert-info">
9
+ <%= flash[:notice] %>
10
+ </div>
11
+ <% end %>
12
+
13
+ <%= yield %>
@@ -0,0 +1,22 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <title><%= t("goodmin.title") %></title>
5
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
6
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/css/bootstrap-datetimepicker.min.css">
7
+ <%= stylesheet_link_tag "goodmin/application", media: "all" %>
8
+
9
+ <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
10
+ <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
11
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js"></script>
12
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.17.47/js/bootstrap-datetimepicker.min.js"></script>
13
+ <%= javascript_importmap_tags "goodmin/application", importmap: Goodmin.importmap %>
14
+
15
+ <%= csrf_meta_tags %>
16
+ <meta name="viewport" content="width=device-width, initial-scale=1">
17
+ <%= yield :head %>
18
+ </head>
19
+ <body data-controller="navigation">
20
+ <%= yield :body %>
21
+ </body>
22
+ </html>
@@ -0,0 +1,28 @@
1
+ <% content_for :body do %>
2
+ <nav class="navbar navbar-default navbar-static-top" role="navigation">
3
+ <div class="container">
4
+ <div class="navbar-header">
5
+ <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#goodmin-navbar-collapse" aria-expanded="false">
6
+ <span class="sr-only">Toggle navigation</span>
7
+ <span class="icon-bar"></span>
8
+ <span class="icon-bar"></span>
9
+ <span class="icon-bar"></span>
10
+ </button>
11
+ <%= link_to t("goodmin.title"), root_path, class: "navbar-brand" %>
12
+ </div>
13
+ <div class="collapse navbar-collapse" id="goodmin-navbar-collapse">
14
+ <ul class="nav navbar-nav">
15
+ <%= render 'goodmin/shared/navigation' %>
16
+ </ul>
17
+ <ul class="nav navbar-nav navbar-right">
18
+ <%= render 'goodmin/shared/navigation_aside' %>
19
+ </ul>
20
+ </div>
21
+ </div>
22
+ </nav>
23
+ <div class="container">
24
+ <%= render "layouts/goodmin/content" %>
25
+ </div>
26
+ <% end %>
27
+
28
+ <%= render "layouts/goodmin/layout" %>
@@ -0,0 +1,18 @@
1
+ <% content_for :body do %>
2
+ <div id="login" class="container">
3
+ <div class="row">
4
+ <div class="col-md-4 col-md-offset-4">
5
+ <div class="panel panel-default">
6
+ <div class="panel-heading">
7
+ <h3 class="panel-title"><%= t("goodmin.title") %></h3>
8
+ </div>
9
+ <div class="panel-body">
10
+ <%= render "layouts/goodmin/content" %>
11
+ </div>
12
+ </div>
13
+ </div>
14
+ </div>
15
+ </div>
16
+ <% end %>
17
+
18
+ <%= render "layouts/goodmin/layout" %>
@@ -0,0 +1,5 @@
1
+ pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
2
+ pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
3
+
4
+ pin "goodmin/application", to: "goodmin/application.js", preload: true
5
+ pin_all_from Goodmin::Engine.root.join("app/javascript/goodmin/controllers"), under: "controllers", to: "goodmin/controllers"