cm-admin 0.8.9 → 0.9.0

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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/.stylelintrc.json +3 -0
  3. data/.github/workflows/linters.yml +31 -0
  4. data/Gemfile +5 -1
  5. data/Gemfile.lock +23 -10
  6. data/app/assets/stylesheets/cm_admin/base/auth.scss +1 -1
  7. data/app/assets/stylesheets/cm_admin/base/common.scss +3 -3
  8. data/app/assets/stylesheets/cm_admin/base/filters.scss +11 -17
  9. data/app/assets/stylesheets/cm_admin/base/form.scss +6 -12
  10. data/app/assets/stylesheets/cm_admin/base/main-nav.scss +3 -7
  11. data/app/assets/stylesheets/cm_admin/base/navbar.scss +3 -2
  12. data/app/assets/stylesheets/cm_admin/base/quicksearch.scss +4 -6
  13. data/app/assets/stylesheets/cm_admin/base/scaffold.scss +45 -2
  14. data/app/assets/stylesheets/cm_admin/base/show.scss +11 -9
  15. data/app/assets/stylesheets/cm_admin/base/sidebar.scss +9 -19
  16. data/app/assets/stylesheets/cm_admin/base/table.scss +258 -325
  17. data/app/assets/stylesheets/cm_admin/base/tabs.scss +1 -2
  18. data/app/assets/stylesheets/cm_admin/components/_buttons.scss +19 -6
  19. data/app/assets/stylesheets/cm_admin/components/_drawer.scss +4 -8
  20. data/app/assets/stylesheets/cm_admin/components/_dropdown-popup.scss +1 -2
  21. data/app/assets/stylesheets/cm_admin/components/_input.scss +1 -1
  22. data/app/assets/stylesheets/cm_admin/components/_status-tag.scss +3 -2
  23. data/app/assets/stylesheets/cm_admin/helpers/_variable.scss +4 -0
  24. data/app/assets/stylesheets/cm_admin/scaffold.scss +2 -2
  25. data/app/controllers/cm_admin/resource_controller.rb +4 -2
  26. data/app/javascript/packs/cm_admin/filters.js +1 -1
  27. data/app/javascript/packs/cm_admin/scaffolds.js +4 -1
  28. data/app/views/cm_admin/main/_actions_dropdown.html.slim +2 -2
  29. data/app/views/cm_admin/main/_associated_table.html.slim +20 -21
  30. data/app/views/cm_admin/main/_member_custom_action_modal.html.slim +1 -1
  31. data/app/views/cm_admin/main/_table.html.slim +13 -14
  32. data/app/views/cm_admin/main/associated_index.html.slim +4 -5
  33. data/app/views/cm_admin/main/index.html.slim +13 -14
  34. data/app/views/cm_admin/main/show.html.slim +2 -2
  35. data/app/views/layouts/cm_admin.html.slim +5 -5
  36. data/lib/cm_admin/model.rb +6 -1
  37. data/lib/cm_admin/models/action.rb +1 -1
  38. data/lib/cm_admin/models/column.rb +16 -3
  39. data/lib/cm_admin/models/dsl_method.rb +17 -4
  40. data/lib/cm_admin/models/field.rb +7 -1
  41. data/lib/cm_admin/models/utils/associations.rb +25 -0
  42. data/lib/cm_admin/version.rb +1 -1
  43. data/lib/cm_admin/view_helpers/field_display_helper.rb +21 -1
  44. data/lib/cm_admin/view_helpers/page_info_helper.rb +7 -3
  45. data/package-lock.json +2801 -158
  46. data/package.json +2 -0
  47. data/tmp/cache/webpacker/last-compilation-digest-development +1 -1
  48. data/yarn.lock +6949 -5133
  49. metadata +5 -2
@@ -1,14 +1,16 @@
1
1
  @import '../helpers/index.scss';
2
2
 
3
3
  .cta-btn {
4
- padding: 8px 16px;
4
+ padding: 5px 10px;
5
5
  @include font($size: $t4-text, $color: $white, $weight: bold);
6
6
  background-color: $brand-color;
7
7
  border: none;
8
8
  border-radius: $radius-4;
9
9
  transition: all .2s linear;
10
10
  &:hover {
11
- background-color: #4D40AA;
11
+ color: $white;
12
+ background: $cta-hover-gradient;
13
+ transform: scale(1.05);
12
14
  }
13
15
  &:focus {
14
16
  outline: 3px auto rgba(47, 128, 237, 0.3);
@@ -25,14 +27,16 @@
25
27
  }
26
28
 
27
29
  .primary-btn {
28
- padding: 8px 16px;
30
+ padding: 5px 10px;
29
31
  @include font($size: $t4-text, $color: $brand-color, $weight: bold);
30
32
  background-color: $white;
31
33
  border: 1px solid $brand-color;
32
34
  border-radius: $radius-4;
33
35
  transition: all .2s linear;
34
36
  &:hover {
37
+ color: $brand-color;
35
38
  background-color: #E6E4FA;
39
+ transform: scale(1.05);
36
40
  }
37
41
  &:focus {
38
42
  outline: 3px auto rgba(47, 128, 237, 0.3);
@@ -50,14 +54,16 @@
50
54
  }
51
55
 
52
56
  .secondary-btn {
53
- padding: 8px 16px;
57
+ padding: 5px 10px;
54
58
  @include font($size: $t4-text, $color: $primary-text-clr, $weight: bold);
55
59
  background-color: $white;
56
60
  border: 1px solid $ink-regular-clr;
57
61
  border-radius: $radius-4;
58
62
  transition: all .2s linear;
59
63
  &:hover {
64
+ color: $primary-text-clr;
60
65
  background-color: $grey-light-clr;
66
+ transform: scale(1.05);
61
67
  }
62
68
  &:focus {
63
69
  outline: 3px auto rgba(47, 128, 237, 0.3);
@@ -75,17 +81,22 @@
75
81
  span:nth-child(2) {
76
82
  margin: 0 4px 0 8px;
77
83
  }
84
+ span:nth-child(3) {
85
+ @include font($size: 10px, $color: $ink-lighter-clr, $weight: bold);
86
+ }
78
87
  }
79
88
 
80
89
  .gray-border-btn {
81
- padding: 7px 16px;
90
+ padding: 5px 10px;
82
91
  @include font($size: $t4-text, $color: $primary-text-clr, $weight: bold);
83
92
  background-color: $white;
84
93
  border: 1px solid $ink-regular-clr;
85
94
  border-radius: $radius-4;
86
95
  transition: all .2s linear;
87
96
  &:hover {
97
+ color: $primary-text-clr;
88
98
  background-color: $grey-light-clr;
99
+ transform: scale(1.05);
89
100
  }
90
101
  &:focus {
91
102
  outline: 3px auto rgba(47, 128, 237, 0.3);
@@ -103,14 +114,16 @@
103
114
  }
104
115
 
105
116
  .ghost-btn {
106
- padding: 8px 16px;
117
+ padding: 5px 10px;
107
118
  @include font($size: $t4-text, $color: $primary-text-clr, $weight: bold);
108
119
  background-color: transparent;
109
120
  border: none;
110
121
  border-radius: $radius-4;
111
122
  transition: all .2s linear;
112
123
  &:hover {
124
+ color: $primary-text-clr;
113
125
  background: $grey-light-clr;
126
+ transform: scale(1.05);
114
127
  }
115
128
  &:focus {
116
129
  outline: 3px auto rgba(47, 128, 237, 0.3);
@@ -21,21 +21,18 @@
21
21
  align-items: center;
22
22
  justify-content: space-between;
23
23
  padding: 24px;
24
- background: #F8F9FA;
24
+ background: $grey-lightest-clr;
25
25
  &__lhs {
26
26
  .title {
27
+ @include font($size: $t1-text, $color: $primary-text-clr, $weight: 600);
27
28
  font-family: $primary-font;
28
- font-size: $t1-text;
29
- font-weight: 600;
30
29
  line-height: 28px;
31
- color: $primary-text-clr;
32
30
  margin-bottom: 8px;
33
31
  }
34
32
  .description {
33
+ @include font($size: $t4-text, $color: $primary-text-clr);
35
34
  font-family: $primary-font;
36
- font-size: $t4-text;
37
35
  line-height: 22px;
38
- color: $primary-text-clr;
39
36
  margin-bottom: 0;
40
37
  }
41
38
  }
@@ -46,10 +43,9 @@
46
43
  .body {
47
44
  padding: 24px;
48
45
  .info-text {
46
+ @include font($size: $t4-text, $color: $primary-text-clr);
49
47
  font-family: $primary-font;
50
- font-size: $t4-text;
51
48
  line-height: 22px;
52
- color: $primary-text-clr;
53
49
  }
54
50
  }
55
51
  }
@@ -143,9 +143,8 @@
143
143
  }
144
144
  }
145
145
  .cannot-sort {
146
- font-size: $t6-text;
146
+ @include font($size: $t6-text, $color: $ink-lightest-clr);
147
147
  line-height: 16px;
148
- color: $ink-lightest-clr;
149
148
  margin-bottom: 9px;
150
149
  padding: 0 16px;
151
150
  }
@@ -38,7 +38,7 @@
38
38
  .search-input {
39
39
  position: relative;
40
40
  width: 100%;
41
- padding: 8px 0 8px 40px;
41
+ padding: 5px 0 5px 38px;
42
42
  @include font($size: $t4-text, $color: $primary-text-clr);
43
43
  line-height: 22px;
44
44
  background-color: $white;
@@ -6,6 +6,7 @@
6
6
  padding: 4px;
7
7
  color: $primary-text-clr;
8
8
  background: $grey-lighter-clr;
9
+ border-radius: 2px;
9
10
  &.success {
10
11
  color: $green-regular-clr;
11
12
  background: $green-lightest-clr;
@@ -25,7 +26,7 @@
25
26
  cursor: pointer;
26
27
  user-select: none;
27
28
  &:hover {
28
- background-color: #F3F4F6;
29
+ background-color: $grey-lighter-clr;
29
30
  .filter-chip-remove {
30
31
  display: block;
31
32
  }
@@ -42,7 +43,7 @@
42
43
  top: 0;
43
44
  right: 0;
44
45
  padding: 4px 16px;
45
- background: linear-gradient(270deg, #F3F4F6 81.75%, rgba(243, 244, 246, 0) 100%);
46
+ background: $gradient-one;
46
47
  border-radius: $radius-4;
47
48
  i {
48
49
  font-size: 10px;
@@ -51,6 +51,10 @@ $subdued-text-clr: #D9DEE3;
51
51
  $white: #FFFFFF;
52
52
  $black: #000000;
53
53
 
54
+ // Gradient Colors
55
+ $gradient-one: linear-gradient(270deg, $grey-lighter-clr 81.75%, rgba(243, 244, 246, 0) 100%);
56
+ $cta-hover-gradient: linear-gradient(0deg, rgba(0, 0, 0, 0.24), rgba(0, 0, 0, 0.24)), $brand-color;
57
+
54
58
  /* Typography */
55
59
  $primary-font: 'Open Sans', sans-serif;
56
60
  $font-size: (
@@ -2,7 +2,7 @@
2
2
 
3
3
  .jGrowl {
4
4
  color: $ink-regular-clr !important;
5
- font-size: 14px !important;
5
+ font-size: $t4-text !important;
6
6
  .success{
7
7
  background-color: $green-light-clr !important;
8
8
  }
@@ -17,7 +17,7 @@
17
17
 
18
18
  .nested-field-wrapper {
19
19
  label {
20
- font-size: 14px;
20
+ font-size: $t4-text;
21
21
  margin-bottom: 16px;
22
22
  }
23
23
  .nested-fields {
@@ -193,7 +193,9 @@ module CmAdmin
193
193
  end
194
194
 
195
195
  def resource_params(params)
196
- permittable_fields = @permitted_fields || @model.ar_model.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym)
196
+ columns = @model.ar_model.column_names
197
+ columns += @model.ar_model.stored_attributes.values.flatten
198
+ permittable_fields = @model.additional_permitted_fields + columns.reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym)
197
199
  permittable_fields += @model.ar_model.name.constantize.reflect_on_all_associations.map {|x|
198
200
  next if x.options[:polymorphic]
199
201
  if x.class.name.include?('HasOne')
@@ -207,7 +209,7 @@ module CmAdmin
207
209
  nested_fields = nested_tables.uniq.map {|table|
208
210
  Hash[
209
211
  table.to_s + '_attributes',
210
- table.to_s.classify.constantize.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym) + [:id, :_destroy]
212
+ table.to_s.classify.constantize.column_names.reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym) + [:id, :_destroy]
211
213
  ]
212
214
  }
213
215
  permittable_fields += nested_fields
@@ -54,7 +54,7 @@ var getFilteredData = function(filterType, filterValue, filterColumn=null) {
54
54
  success: function(data) {
55
55
  var queryParam = jQuery.param(queryString)
56
56
  window.history.pushState("", "", url + '?' + queryParam);
57
- $('.index-page__table-container').html(data);
57
+ $('.cm-index-page__table-container').html(data);
58
58
  },
59
59
  error: function(jqxhr, textStatus, errorThrown) {
60
60
  console.log(errorThrown, textStatus);
@@ -16,6 +16,9 @@ $(document).on('turbolinks:load', function () {
16
16
  animation: 150
17
17
  });
18
18
  }
19
+ var headerElemHeight = $('.page-top-bar').height() + 64
20
+ var calculatedHeight = "calc(100vh - " + headerElemHeight+"px"+")"
21
+ $('.new-admin-table').css("maxHeight", calculatedHeight);
19
22
  });
20
23
 
21
24
  $(document).on("keypress keyup blur", "[data-behaviour='decimal-only'], [data-behaviour='filter'][data-filter-type='range']", function (e) {
@@ -70,4 +73,4 @@ $(document).on('click', '.drawer-close', function(e) {
70
73
  setTimeout(() => {
71
74
  $('.cm-drawer').addClass('hidden');
72
75
  }, 300);
73
- });
76
+ });
@@ -38,10 +38,10 @@
38
38
  .popup-option
39
39
  span
40
40
  i class="#{custom_action.icon_name}"
41
- = custom_action.name.humanize
41
+ = custom_action_title(custom_action)
42
42
  - when :modal
43
43
  = link_to '', data: { bs_toggle: 'modal', bs_target: "##{custom_action.name.classify}Modal-#{ar_object.id.to_s}" } do
44
44
  .popup-option
45
45
  span
46
46
  i class="#{custom_action.icon_name}"
47
- = custom_action.name.humanize
47
+ = custom_action_title(custom_action)
@@ -1,20 +1,19 @@
1
- .admin-table-index
2
- .table-top
3
- - if @associated_model.filters.present? && @action.partial.nil?
4
- .index-page__filters
5
- == render partial: 'cm_admin/main/filters', locals: { filters: @associated_model.filters }
6
- p.table-top__total-count = "#{humanized_ar_collection_count(@associated_ar_object.pagy.count, @action.child_records.to_s)}"
7
- .table-top__column-action
8
- - if @associated_model && @associated_model.available_actions.map(&:name).include?('new') && has_valid_policy(@associated_model.name, 'new')
9
- - association = @ar_object.class.reflect_on_all_associations.select{|x| x.name == @associated_model.name.tableize.to_sym }.first
10
- - polymorphic_name = (association && association.inverse_of && association.inverse_of.options[:polymorphic]) ? association.inverse_of.name : ''
11
- a href="#{CmAdmin::Engine.mount_path}/#{@associated_model.name.tableize}/new?associated_id=#{@ar_object.id}&associated_class=#{@ar_object.class.name.underscore}&polymorphic_name=#{polymorphic_name}&referrer=#{request.path}"
12
- button.secondary-btn.column-btn Add
13
- / button.secondary-btn.column-btn data-target="#columnActionModal" data-toggle="modal" type="button"
14
- / span
15
- / i.fa.fa-columns.bolder
16
- / span
17
- / i.fa.fa-angle-down
1
+ .table-top
2
+ - if @associated_model.filters.present? && @action.partial.nil?
3
+ .cm-index-page__filters
4
+ == render partial: 'cm_admin/main/filters', locals: { filters: @associated_model.filters }
5
+ p.table-top__total-count = "#{humanized_ar_collection_count(@associated_ar_object.pagy.count, @action.child_records.to_s)}"
6
+ .table-top__column-action
7
+ - if @associated_model && @associated_model.available_actions.map(&:name).include?('new') && has_valid_policy(@associated_model.name, 'new')
8
+ - association = @ar_object.class.reflect_on_all_associations.select{|x| x.name == @associated_model.name.tableize.to_sym }.first
9
+ - polymorphic_name = (association && association.inverse_of && association.inverse_of.options[:polymorphic]) ? association.inverse_of.name : ''
10
+ a href="#{CmAdmin::Engine.mount_path}/#{@associated_model.name.tableize}/new?associated_id=#{@ar_object.id}&associated_class=#{@ar_object.class.name.underscore}&polymorphic_name=#{polymorphic_name}&referrer=#{request.path}"
11
+ button.secondary-btn.column-btn Add
12
+ / button.secondary-btn.column-btn data-target="#columnActionModal" data-toggle="modal" type="button"
13
+ / span
14
+ / i.fa.fa-columns.bolder
15
+ / span
16
+ / i.fa.fa-angle-down
18
17
 
19
18
  .new-admin-table.scrollable
20
19
  table.cm-table
@@ -46,9 +45,9 @@
46
45
  - if @associated_model
47
46
  == render partial: 'cm_admin/main/actions_dropdown', locals: { cm_model: @associated_model, ar_object: ar_object }
48
47
 
49
- .cm-pagination
50
- .cm-pagination__lhs Showing #{@associated_ar_object.pagy.from} to #{@associated_ar_object.pagy.to} out of #{@associated_ar_object.pagy.count}
51
- .cm-pagination__rhs
52
- == render partial: 'cm_admin/main/cm_pagy_nav', locals: { pagy: @associated_ar_object.pagy }
48
+ .cm-pagination
49
+ .cm-pagination__lhs Showing #{@associated_ar_object.pagy.from} to #{@associated_ar_object.pagy.to} out of #{@associated_ar_object.pagy.count}
50
+ .cm-pagination__rhs
51
+ == render partial: 'cm_admin/main/cm_pagy_nav', locals: { pagy: @associated_ar_object.pagy }
53
52
 
54
53
  = render partial: 'cm_admin/main/member_custom_action_modal', locals: { cm_model: @associated_model, ar_collection: @associated_ar_object }
@@ -7,7 +7,7 @@
7
7
  .modal-dialog
8
8
  .modal-content
9
9
  .modal-header
10
- h5.modal-title id="#{custom_action.name.classify}ModalLabel" = custom_action.name.classify
10
+ h5.modal-title id="#{custom_action.name.classify}ModalLabel" = custom_action_title(custom_action)
11
11
  button.btn-close aria-label='Close' data-bs-dismiss='modal'
12
12
  .modal-body
13
13
  = render partial: custom_action.partial, locals: { ar_object: ar_object }
@@ -1,13 +1,12 @@
1
- .admin-table-index
2
- .table-top
3
- p.table-top__total-count = "#{humanized_ar_collection_count(@ar_object.pagy.count, @model.ar_model.table_name)}"
4
- // .table-top__column-action
5
- // button.secondary-btn.column-btn data-bs-target="#columnActionModal" data-bs-toggle="modal"
6
- // span
7
- // i.fa.fa-columns.bolder
8
- // span
9
- // i.fa.fa-angle-down
10
- .new-admin-table.scrollable
1
+ .table-top
2
+ p.table-top__total-count = "#{humanized_ar_collection_count(@ar_object.pagy.count, @model.ar_model.table_name)}"
3
+ // .table-top__column-action
4
+ // button.secondary-btn.column-btn data-bs-target="#columnActionModal" data-bs-toggle="modal"
5
+ // span
6
+ // i.fa.fa-columns.bolder
7
+ // span
8
+ // i.fa.fa-angle-down
9
+ .new-admin-table
11
10
  table.cm-table
12
11
  thead.cm-table__header
13
12
  tr.header-row
@@ -37,9 +36,9 @@
37
36
  - if @model
38
37
  == render partial: 'cm_admin/main/actions_dropdown', locals: { cm_model: @model, ar_object: ar_object }
39
38
 
40
- .cm-pagination
41
- .cm-pagination__lhs Showing #{@ar_object.pagy.from} to #{@ar_object.pagy.to} out of #{@ar_object.pagy.count}
42
- .cm-pagination__rhs
43
- == render partial: 'cm_admin/main/cm_pagy_nav', locals: { pagy: @ar_object.pagy }
39
+ .cm-pagination
40
+ .cm-pagination__lhs Showing #{@ar_object.pagy.from} to #{@ar_object.pagy.to} out of #{@ar_object.pagy.count}
41
+ .cm-pagination__rhs
42
+ == render partial: 'cm_admin/main/cm_pagy_nav', locals: { pagy: @ar_object.pagy }
44
43
 
45
44
  = render partial: 'cm_admin/main/member_custom_action_modal', locals: { cm_model: @model, ar_collection: @ar_object }
@@ -1,6 +1,5 @@
1
- .cm-index-page
2
- .index-page
3
- .index-page__table-container
4
- == render partial: 'cm_admin/main/associated_table'
1
+ .cm-index-page.associated-index
2
+ .cm-index-page__table-container
3
+ == render partial: 'cm_admin/main/associated_table'
5
4
 
6
- // = column_pop_up(@associated_model)
5
+ // = column_pop_up(@associated_model)
@@ -1,16 +1,15 @@
1
- .cm-index-page
2
- .index-page.page-container
3
- .sticky-container
4
- == render 'cm_admin/main/top_navbar'
5
- - if @model.filters.present? && @action.partial.nil?
6
- .index-page__filters
7
- == render partial: 'cm_admin/main/filters', locals: { filters: @model.filters }
8
- .index-page__table-container
9
- - if @action.partial
10
- == render @action.partial
11
- - else
12
- == render 'cm_admin/main/table'
1
+ .cm-index-page.cm-page-container
2
+ .sticky-container.page-top-bar
3
+ == render 'cm_admin/main/top_navbar'
4
+ - if @model.filters.present? && @action.partial.nil?
5
+ .cm-index-page__filters
6
+ == render partial: 'cm_admin/main/filters', locals: { filters: @model.filters }
7
+ .cm-index-page__table-container
8
+ - if @action.partial
9
+ == render @action.partial
10
+ - else
11
+ == render 'cm_admin/main/table'
13
12
 
14
- = column_pop_up(@model)
15
- = manage_column_pop_up(@model)
13
+ = column_pop_up(@model)
14
+ = manage_column_pop_up(@model)
16
15
 
@@ -1,5 +1,5 @@
1
- .show-page.page-container
2
- .show-page__tabs.sticky-container
1
+ .show-page.cm-page-container
2
+ .show-page__tabs.sticky-container.page-top-bar
3
3
  .cm-tabs-bar
4
4
  == render 'cm_admin/main/top_navbar'
5
5
  == render 'cm_admin/main/tabs'
@@ -19,21 +19,21 @@ html
19
19
  = render 'layouts/left_sidebar_nav'
20
20
  .panel-area
21
21
  - if defined?(@action) && (@action&.layout_type.to_s == 'cm_association_show' || @action.parent == "show")
22
- .show-page.page-container
23
- .show-page__tabs.sticky-container
22
+ .show-page.cm-page-container
23
+ .show-page__tabs.sticky-container.page-top-bar
24
24
  .cm-tabs-bar
25
25
  == render 'cm_admin/main/top_navbar'
26
26
  == render 'cm_admin/main/tabs'
27
27
  .show-page__inner.scrollable
28
28
  = yield
29
29
  - elsif defined?(@action) && (@action&.layout_type.to_s == 'cm_association_index' || @action.parent == "index")
30
- .show-page.page-container
31
- .show-page__tabs.sticky-container
30
+ .show-page.cm-page-container
31
+ .show-page__tabs.sticky-container.page-top-bar
32
32
  .cm-tabs-bar
33
33
  == render 'cm_admin/main/top_navbar'
34
34
  == render 'cm_admin/main/tabs'
35
35
  - if @associated_model && @associated_model.filters.present?
36
- .index-page__filters
36
+ .filters-bar
37
37
  == render partial: 'cm_admin/main/filters', locals: { filters: @associated_model.filters }
38
38
  = yield
39
39
  - else
@@ -23,7 +23,7 @@ module CmAdmin
23
23
  include Pagy::Backend
24
24
  include Models::Blocks
25
25
  include Models::DslMethod
26
- attr_accessor :available_actions, :actions_set, :available_fields, :permitted_fields,
26
+ attr_accessor :available_actions, :actions_set, :available_fields, :additional_permitted_fields,
27
27
  :current_action, :params, :filters, :available_tabs, :icon_name
28
28
  attr_reader :name, :ar_model, :is_visible_on_sidebar, :importer
29
29
 
@@ -33,6 +33,7 @@ module CmAdmin
33
33
  @is_visible_on_sidebar = true
34
34
  @icon_name = 'fa fa-th-large'
35
35
  @available_actions ||= []
36
+ @additional_permitted_fields ||= []
36
37
  @current_action = nil
37
38
  @available_tabs ||= []
38
39
  @available_fields ||= {index: [], show: [], edit: {fields: []}, new: {fields: []}}
@@ -94,6 +95,10 @@ module CmAdmin
94
95
  @icon_name = name
95
96
  end
96
97
 
98
+ def permit_additional_fields(fields=[])
99
+ @additional_permitted_fields = fields
100
+ end
101
+
97
102
  # Shared between export controller and resource controller
98
103
  def filter_params(params)
99
104
  # OPTIMIZE: Need to check if we can permit the filter_params in a better way
@@ -4,7 +4,7 @@ module CmAdmin
4
4
  module Models
5
5
  class Action
6
6
  include Actions::Blocks
7
- attr_accessor :name, :verb, :layout_type, :layout, :partial, :path, :page_title, :page_description,
7
+ attr_accessor :name, :display_name, :verb, :layout_type, :layout, :partial, :path, :page_title, :page_description,
8
8
  :child_records, :is_nested_field, :nested_table_name, :parent, :display_if, :route_type, :code_block,
9
9
  :display_type, :action_type, :redirection_url, :sort_direction, :sort_column, :icon_name
10
10
 
@@ -1,8 +1,13 @@
1
+ require_relative 'utils/associations'
2
+
1
3
  module CmAdmin
2
4
  module Models
3
5
  class Column
6
+ include Utils::Associations
7
+
4
8
  attr_accessor :field_name, :field_type, :header, :format, :prefix, :suffix, :exportable, :round, :height, :width,
5
- :cm_css_class, :link, :url, :custom_method, :helper_method, :managable, :lockable, :drawer_partial, :tag_class, :display_if
9
+ :cm_css_class, :link, :url, :custom_method, :helper_method, :managable, :lockable, :drawer_partial, :tag_class,
10
+ :display_if, :association_name, :association_type
6
11
 
7
12
  def initialize(field_name, attributes = {})
8
13
  @field_name = field_name
@@ -16,11 +21,20 @@ module CmAdmin
16
21
  self.height = 50 if self.field_type == :image && self.height.nil?
17
22
  self.width = 50 if self.field_type == :image && self.width.nil?
18
23
  self.display_if = lambda { |arg| return true } if self.display_if.nil?
24
+
25
+ validation_for_association
19
26
  end
20
27
 
21
28
  #returns a string value as a header (either field_name or value present in header attribute)
22
29
  def format_header
23
- self.header.present? ? self.header.to_s.gsub(/_/, ' ')&.upcase : self.field_name.to_s.gsub(/_/, ' ').upcase
30
+ header_value = if self.header.present?
31
+ self.header
32
+ elsif self.field_type.to_s == 'association'
33
+ self.association_name
34
+ else
35
+ self.field_name
36
+ end
37
+ header_value.to_s.titleize.upcase
24
38
  end
25
39
 
26
40
  def set_default_values
@@ -35,7 +49,6 @@ module CmAdmin
35
49
  model.available_fields.find { |i| i.name == search_hash[:name] }
36
50
  end
37
51
  end
38
-
39
52
  end
40
53
  end
41
54
  end
@@ -77,10 +77,23 @@ module CmAdmin
77
77
  def column(field_name, options={})
78
78
  @available_fields[@current_action.name.to_sym] ||= []
79
79
  if @available_fields[@current_action.name.to_sym].select{|x| x.lockable}.size > 0 && options[:lockable]
80
- raise "Only one column can be locked in a table."
80
+ raise 'Only one column can be locked in a table.'
81
81
  end
82
82
 
83
- unless @available_fields[@current_action.name.to_sym].map{|x| x.field_name.to_sym}.include?(field_name)
83
+ duplicate_columns = @available_fields[@current_action.name.to_sym].filter{|x| x.field_name.to_sym == field_name}
84
+ terminate = false
85
+
86
+ if duplicate_columns.size.positive?
87
+ duplicate_columns.each do |column|
88
+ if options[:field_type].to_s != 'association'
89
+ terminate = true
90
+ elsif options[:field_type].to_s == 'association' && column.association_name.to_s == options[:association_name].to_s
91
+ terminate = true
92
+ end
93
+ end
94
+ end
95
+
96
+ unless terminate
84
97
  @available_fields[@current_action.name.to_sym] << CmAdmin::Models::Column.new(field_name, options)
85
98
  end
86
99
  end
@@ -107,9 +120,9 @@ module CmAdmin
107
120
  # end
108
121
  # end
109
122
  # end
110
- def custom_action(name: nil, verb: nil, layout: nil, layout_type: nil, partial: nil, path: nil, display_type: nil, display_if: lambda { |arg| return true }, route_type: nil, icon_name: 'fa fa-th-large', &block)
123
+ def custom_action(name: nil, display_name: nil, verb: nil, layout: nil, layout_type: nil, partial: nil, path: nil, display_type: nil, display_if: lambda { |arg| return true }, route_type: nil, icon_name: 'fa fa-th-large', &block)
111
124
  action = CmAdmin::Models::CustomAction.new(
112
- name: name, verb: verb, layout: layout, layout_type: layout_type, partial: partial, path: path,
125
+ name: name, display_name: display_name, verb: verb, layout: layout, layout_type: layout_type, partial: partial, path: path,
113
126
  parent: self.current_action.name, display_type: display_type, display_if: display_if,
114
127
  action_type: :custom, route_type: route_type, icon_name: icon_name, &block)
115
128
  @available_actions << action
@@ -1,9 +1,13 @@
1
+ require_relative 'utils/associations'
2
+
1
3
  module CmAdmin
2
4
  module Models
3
5
  class Field
6
+ include Utils::Associations
4
7
 
5
8
  attr_accessor :field_name, :label, :header, :field_type, :format, :precision, :height,
6
- :width, :helper_method, :preview, :custom_link, :precision, :prefix, :suffix, :tag_class, :display_if
9
+ :width, :helper_method, :preview, :custom_link, :prefix, :suffix, :tag_class,
10
+ :display_if, :association_name, :association_type
7
11
 
8
12
  def initialize(field_name, attributes = {})
9
13
  @field_name = field_name
@@ -14,6 +18,8 @@ module CmAdmin
14
18
  self.height = 50 if self.field_type == :image && self.height.nil?
15
19
  self.width = 50 if self.field_type == :image && self.width.nil?
16
20
  self.display_if = lambda { |arg| return true } if self.display_if.nil?
21
+
22
+ validation_for_association
17
23
  end
18
24
 
19
25
  def set_default_values
@@ -0,0 +1,25 @@
1
+ module CmAdmin
2
+ module Models
3
+ module Utils
4
+ module Associations
5
+ extend ActiveSupport::Concern
6
+
7
+ def validation_for_association
8
+ return unless field_type.to_s == "association"
9
+
10
+ raise ArgumentError, 'Expected association_name and association_type to be present' if association_name.nil? || association_type.nil?
11
+
12
+ if association_type.to_s == 'polymorphic'
13
+ raise ArgumentError, "Expected field_name - #{field_name} - to be an array of hash. Eg, [{table_name_1: 'column_name_1'}, {table_name_2: 'column_name_2'}]" unless field_name.is_a?(Array)
14
+
15
+ field_name.each do |element|
16
+ raise ArgumentError, "Expected element #{element} to be a hash. Eg, [{table_name_1: 'column_name_1'}, {table_name_2: 'column_name_2'}]" unless element.is_a?(Hash)
17
+ end
18
+ elsif ['belongs_to', 'has_one'].include? association_type.to_s
19
+ raise ArgumentError, "Expected field_name - #{field_name} to be a String or Symbol" unless field_name.is_a?(Symbol) || field_name.is_a?(String)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module CmAdmin
2
- VERSION = '0.8.9'
2
+ VERSION = '0.9.0'
3
3
  end