cm-admin 1.1.7 → 1.1.9

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 (40) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.vscode/settings.json +3 -0
  4. data/Gemfile.lock +1 -1
  5. data/app/assets/javascripts/cm_admin/scaffolds.js +1 -1
  6. data/app/assets/stylesheets/cm_admin/base/navbar.scss +13 -39
  7. data/app/assets/stylesheets/cm_admin/base/quicksearch.scss +3 -4
  8. data/app/assets/stylesheets/cm_admin/base/show.scss +4 -15
  9. data/app/assets/stylesheets/cm_admin/base/table.scss +2 -14
  10. data/app/assets/stylesheets/cm_admin/cm_admin.css.scss +1 -0
  11. data/app/assets/stylesheets/cm_admin/components/_buttons.scss +29 -135
  12. data/app/assets/stylesheets/cm_admin/dependency/bootstrap.min.css +4 -5
  13. data/app/assets/stylesheets/cm_admin/dependency/jquery-jgrowl.min.css +1 -0
  14. data/app/assets/stylesheets/cm_admin/helpers/_variable.scss +31 -30
  15. data/app/assets/stylesheets/cm_admin/pages/import_page.scss +3 -10
  16. data/app/controllers/cm_admin/resource_controller.rb +13 -9
  17. data/app/views/cm_admin/main/_actions_dropdown.html.slim +1 -3
  18. data/app/views/cm_admin/main/_associated_table.html.slim +1 -1
  19. data/app/views/cm_admin/main/_nested_fields.html.slim +2 -1
  20. data/app/views/cm_admin/main/_nested_table_form.html.slim +1 -1
  21. data/app/views/cm_admin/main/_tabs.html.slim +1 -1
  22. data/app/views/cm_admin/main/_top_navbar.html.slim +11 -17
  23. data/app/views/cm_admin/main/history.html.slim +3 -4
  24. data/app/views/cm_admin/main/import_form.html.slim +2 -2
  25. data/app/views/cm_admin/main/new.html.slim +1 -1
  26. data/app/views/cm_admin/main/show.html.slim +3 -4
  27. data/app/views/layouts/_cm_flash_message.html.slim +3 -3
  28. data/app/views/layouts/_quick_links.html.slim +2 -2
  29. data/app/views/layouts/cm_admin.html.slim +10 -12
  30. data/lib/cm_admin/models/filter.rb +55 -29
  31. data/lib/cm_admin/models/form_field.rb +18 -3
  32. data/lib/cm_admin/models/utils/helpers.rb +14 -0
  33. data/lib/cm_admin/version.rb +1 -1
  34. data/lib/cm_admin/view_helpers/filter_helper.rb +1 -1
  35. data/lib/cm_admin/view_helpers/form_field_helper.rb +16 -17
  36. data/lib/cm_admin/view_helpers/form_helper.rb +2 -1
  37. data/lib/cm_admin/view_helpers/manage_column_popup_helper.rb +2 -2
  38. data/lib/cm_admin/view_helpers/page_info_helper.rb +4 -4
  39. data/lib/cm_admin/view_helpers.rb +2 -1
  40. metadata +5 -2
@@ -0,0 +1 @@
1
+ .jGrowl{z-index:9999;color:#fff;font-size:12px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;position:fixed}.jGrowl.top-left{left:0;top:0}.jGrowl.top-right{right:0;top:0}.jGrowl.bottom-left{left:0;bottom:0}.jGrowl.bottom-right{right:0;bottom:0}.jGrowl.center{top:0;width:50%;left:25%}.jGrowl.center .jGrowl-closer,.jGrowl.center .jGrowl-notification{margin-left:auto;margin-right:auto}.jGrowl-notification{background-color:#000;opacity:.9;zoom:1;width:250px;padding:10px;margin:10px;text-align:left;display:none;border-radius:5px;min-height:40px}.jGrowl-notification .ui-state-highlight,.jGrowl-notification .ui-widget-content .ui-state-highlight,.jGrowl-notification .ui-widget-header .ui-state-highlight{border:1px solid #000;background:#000;color:#fff}.jGrowl-notification .jGrowl-header{font-weight:700;font-size:.85em}.jGrowl-notification .jGrowl-close{background-color:transparent;color:inherit;border:none;z-index:99;float:right;font-weight:700;font-size:1em;cursor:pointer}.jGrowl-closer{background-color:#000;opacity:.9;zoom:1;width:250px;padding:10px;margin:10px;text-align:left;display:none;border-radius:5px;padding-top:4px;padding-bottom:4px;cursor:pointer;font-size:.9em;font-weight:700;text-align:center}.jGrowl-closer .ui-state-highlight,.jGrowl-closer .ui-widget-content .ui-state-highlight,.jGrowl-closer .ui-widget-header .ui-state-highlight{border:1px solid #000;background:#000;color:#fff}@media print{.jGrowl{display:none}}
@@ -1,54 +1,55 @@
1
1
  /* ==== Color Variables ==== */
2
2
 
3
3
  /* Brand Color */
4
- $brand-color: #6554E0;
4
+ $brand-color: #6554e0;
5
+ $brand-hover-color: #e6e4fa;
5
6
 
6
7
  /* Semantic Color */
7
- $informative-clr: #2F80ED;
8
- $error-clr: #F83636;
9
- $warning-clr: #FFC845;
10
- $positive-clr: #30C39E;
11
- $disabled-clr: #9CA7AE;
8
+ $informative-clr: #2f80ed;
9
+ $error-clr: #f83636;
10
+ $warning-clr: #ffc845;
11
+ $positive-clr: #30c39e;
12
+ $disabled-clr: #9ca7ae;
12
13
 
13
14
  /* Blue Colors */
14
- $blue-regular-clr: #2F80ED;
15
- $blue-light-clr: #CDE1FB;
16
- $blue-lightest-clr: #EEF5FE;
15
+ $blue-regular-clr: #2f80ed;
16
+ $blue-light-clr: #cde1fb;
17
+ $blue-lightest-clr: #eef5fe;
17
18
 
18
19
  /* Red Colors */
19
- $red-regular-clr: #F83636;
20
- $red-light-clr: #FDCFCF;
21
- $red-lightest-clr: #FEEFEF;
20
+ $red-regular-clr: #f83636;
21
+ $red-light-clr: #fdcfcf;
22
+ $red-lightest-clr: #feefef;
22
23
 
23
24
  /* Yellow Colors */
24
- $yellow-regular-clr: #FFC845;
25
- $yellow-light-clr: #FFEFC7;
26
- $yellow-lightest-clr: #FFF8E9;
25
+ $yellow-regular-clr: #ffc845;
26
+ $yellow-light-clr: #ffefc7;
27
+ $yellow-lightest-clr: #fff8e9;
27
28
 
28
29
  /* Green Colors */
29
- $green-regular-clr: #30C39E;
30
- $green-light-clr: #C1EDE2;
31
- $green-lightest-clr: #EEFAF7;
30
+ $green-regular-clr: #30c39e;
31
+ $green-light-clr: #c1ede2;
32
+ $green-lightest-clr: #eefaf7;
32
33
 
33
34
  /* Grey Colors */
34
- $grey-regular-clr: #C7CED5;
35
- $grey-light-clr: #D9DEE3;
36
- $grey-lighter-clr: #F3F4F6;
37
- $grey-lightest-clr: #F8F9FA;
35
+ $grey-regular-clr: #c7ced5;
36
+ $grey-light-clr: #d9dee3;
37
+ $grey-lighter-clr: #f3f4f6;
38
+ $grey-lightest-clr: #f8f9fa;
38
39
  $grey-dark-clr: #828282;
39
40
 
40
41
  /* Ink Colors */
41
- $ink-regular-clr: #1D2129;
42
- $ink-light-clr: #3B4352;
43
- $ink-lighter-clr: #6B7586;
44
- $ink-lightest-clr: #9CA7AE;
42
+ $ink-regular-clr: #1d2129;
43
+ $ink-light-clr: #3b4352;
44
+ $ink-lighter-clr: #6b7586;
45
+ $ink-lightest-clr: #9ca7ae;
45
46
 
46
47
  /* Text Colors */
47
- $primary-text-clr: #1D2129;
48
- $subdued-text-clr: #D9DEE3;
48
+ $primary-text-clr: #1d2129;
49
+ $subdued-text-clr: #d9dee3;
49
50
 
50
51
  /* Common Colors */
51
- $white: #FFFFFF;
52
+ $white: #ffffff;
52
53
  $black: #000000;
53
54
 
54
55
  // Gradient Colors
@@ -56,7 +57,7 @@ $gradient-one: linear-gradient(270deg, $grey-lighter-clr 81.75%, rgba(243, 244,
56
57
  $cta-hover-gradient: linear-gradient(0deg, rgba(0, 0, 0, 0.24), rgba(0, 0, 0, 0.24)), $brand-color;
57
58
 
58
59
  /* Typography */
59
- $primary-font: 'Open Sans', sans-serif;
60
+ $primary-font: "Open Sans", sans-serif;
60
61
  $font-size: (
61
62
  24: 24px,
62
63
  18: 18px,
@@ -25,7 +25,7 @@
25
25
  line-height: 22px;
26
26
  margin-bottom: 0;
27
27
  }
28
- }
28
+ }
29
29
  &__body {
30
30
  padding: 16px 24px;
31
31
  .body-title {
@@ -63,9 +63,6 @@
63
63
 
64
64
  .actions-wrapper {
65
65
  margin-top: 32px;
66
- button {
67
- padding: 5px 10px;
68
- }
69
66
  }
70
67
 
71
68
  //form UI
@@ -90,7 +87,7 @@
90
87
  margin-bottom: 16px;
91
88
  text-transform: uppercase;
92
89
  }
93
- .steps-wrapper {
90
+ .steps-wrapper {
94
91
  .steps-title {
95
92
  @include font($size: size(16), $weight: bold);
96
93
  font-family: $primary-font;
@@ -116,10 +113,6 @@
116
113
  }
117
114
  }
118
115
  }
119
- .import-btn {
120
- padding: 5px 10px;
121
- }
122
116
  }
123
-
124
117
  }
125
- }
118
+ }
@@ -137,15 +137,19 @@ module CmAdmin
137
137
  data = @action.parent == "index" ? @ar_object.data : @ar_object
138
138
  format.html { render @action.partial }
139
139
  else
140
- response_object = @action.code_block.call(@response_object)
141
- if response_object.class == Hash
142
- format.json { render json: response_object }
143
- elsif response_object.errors.empty?
144
- redirect_url = @model.current_action.redirection_url || @action.redirection_url || request.referrer || "/cm_admin/#{@model.ar_model.table_name}/#{@response_object.id}"
145
- format.html { redirect_to redirect_url, notice: "#{@action.name.titleize} is successful" }
146
- else
147
- error_messages = response_object.errors.full_messages.map{|error_message| "<li>#{error_message}</li>"}.join
148
- format.html { redirect_to request.referrer, alert: "<b>#{@action.name.titleize} is unsuccessful</b><br /><ul>#{error_messages}</ul>" }
140
+ begin
141
+ response_object = @action.code_block.call(@response_object)
142
+ if response_object.class == Hash
143
+ format.json { render json: response_object }
144
+ elsif response_object.errors.empty?
145
+ redirect_url = @model.current_action.redirection_url || @action.redirection_url || request.referrer || "/cm_admin/#{@model.ar_model.table_name}/#{@response_object.id}"
146
+ format.html { redirect_to redirect_url, notice: "#{@action.name.titleize} is successful" }
147
+ else
148
+ error_messages = response_object.errors.full_messages.map{|error_message| "<li>#{error_message}</li>"}.join
149
+ format.html { redirect_to request.referrer, alert: "<b>#{@action.name.titleize} is unsuccessful</b><br /><ul>#{error_messages}</ul>" }
150
+ end
151
+ rescue => exception
152
+ format.html { redirect_to request.referrer, alert: "<b>#{@action.name.titleize} is unsuccessful</b><br /><p>#{exception.message}</p>" }
149
153
  end
150
154
  end
151
155
  end
@@ -5,11 +5,9 @@
5
5
  - if custom_actions.any? || edit_action.present? || destroy_action.present?
6
6
  td.row-action-cell
7
7
  .row-action-tool
8
- button.secondary-btn.tool-btn
8
+ button.btn-ghost.dropdown-toggle
9
9
  span
10
10
  i.fa.fa-bars.bolder
11
- span
12
- i.fa.fa-angle-down
13
11
  .popup-card.table-export-popup.hidden
14
12
  - if edit_action.present?
15
13
  = link_to cm_admin.send("#{current_model.name.underscore}_edit_path", ar_object.id) do
@@ -8,7 +8,7 @@
8
8
  - association = @ar_object.class.reflect_on_all_associations.select{|x| x.name == @associated_model.name.tableize.to_sym }.first
9
9
  - polymorphic_name = (association && association.inverse_of && association.inverse_of.options[:polymorphic]) ? association.inverse_of.name : ''
10
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
11
+ button.btn-secondary Add
12
12
  / button.secondary-btn.column-btn data-target="#columnActionModal" data-toggle="modal" type="button"
13
13
  / span
14
14
  / i.fa.fa-columns.bolder
@@ -15,7 +15,8 @@
15
15
  | Chapter 1
16
16
  .field-remove-action
17
17
  - if @reflections.select {|x| x if x.name == assoc_name}.first.macro == :has_many
18
- = link_to_remove_association "", f, class: 'fa fa-trash ghost-btn accordion-delete-btn'
18
+ .accordion-delete-btn
19
+ = link_to_remove_association "", f, class: 'fa fa-trash btn-ghost'
19
20
  div.accordion-collapse.collapse.show[aria-labelledby="headingOne" id="#{assoc_name}-#{f.object.id}"]
20
21
  .accordion-body
21
22
  - fields.each do |field|
@@ -7,4 +7,4 @@
7
7
  = render partial: '/cm_admin/main/nested_fields', locals: { f: record, assoc_name: assoc_name, section: section }
8
8
  - if @reflections.select {|x| x if x.name == assoc_name}.first.macro == :has_many
9
9
  .links
10
- = link_to_add_association "+ Add #{assoc_name.to_s.titleize}", f, table_name, partial: '/cm_admin/main/nested_fields', render_options: {locals: { assoc_name: assoc_name, section: section }}, class: 'd-inline-block secondary-btn mt-2'
10
+ = link_to_add_association "+ Add #{assoc_name.to_s.titleize}", f, table_name, partial: '/cm_admin/main/nested_fields', render_options: {locals: { assoc_name: assoc_name, section: section }}, class: 'd-inline-block btn-secondary mt-2'
@@ -1,4 +1,4 @@
1
- ul.nav.nav-pills
1
+ ul.tabs
2
2
  - @model.available_tabs.each do |nav_item|
3
3
  - if nav_item.display_if.call(@ar_object)
4
4
  - if nav_item.custom_action.empty? || (nav_item.custom_action.present? && policy([:cm_admin, @model.name.classify.constantize]).send(:"#{nav_item.custom_action}?"))
@@ -1,33 +1,27 @@
1
- .cm-navbar
2
- .cm-navbar__lhs
1
+ .entity-header
2
+ .entity-header__info
3
3
  - if cm_admin.method_defined?(:"#{@model.name.underscore}_index_path") && (@model.current_action.name == 'show' || @model.current_action.layout_type.present?)
4
- .bread-crumb-area
5
- .breadcrumb-text
6
- = link_to "#{@model.name.titleize.pluralize} /", cm_admin.send(:"#{@model.name.underscore}_index_path")
7
- .nav-title-area
8
- p.title-text = action_title
9
- p.title-sub-text = action_description
10
- .cm-navbar__rhs
4
+ .breadcrumb
5
+ = link_to "#{@model.name.titleize.pluralize} /", cm_admin.send(:"#{@model.name.underscore}_index_path"), class: 'text-reset'
6
+ h4 = action_title
7
+ p.mb-0.text-body-secondary = action_description
8
+ .entity-header__actions
11
9
  - if @model.current_action.name == 'index'
12
10
  - if has_valid_policy(@model.name, :exportable)
13
11
  .export-container
14
12
  .dropdown
15
- button.secondary-btn data-bs-toggle='dropdown'
16
- span
13
+ button.btn-secondary.dropdown-toggle data-bs-toggle='dropdown'
17
14
  i.fa.fa-arrow-down
18
- span
19
15
  | Export
20
- span
21
- i.fa.fa-angle-down
22
16
  ul.dropdown-menu.export-popup
23
17
  li
24
18
  .popup-option.pointer data-bs-toggle='modal' data-bs-target='#exportmodal'
25
19
  span Export
26
20
  - if @model.importer && has_valid_policy(@model.name, :importable)
27
- = link_to 'Import', cm_admin.send(:"#{@model.name.underscore}_import_path"), class: 'primary-btn ml-2'
21
+ = link_to 'Import', cm_admin.send(:"#{@model.name.underscore}_import_path"), class: 'btn-primary ml-2'
28
22
  - new_action = @model.available_actions.select{|act| act if act.action_type.eql?(:default) && act.name.eql?('new')}
29
23
  - if new_action.any? && policy([:cm_admin, @model.name.classify.constantize]).new?
30
- = link_to 'Add', cm_admin.send(:"#{@model.name.underscore}_new_path"), class: 'primary-btn ml-2'
24
+ = link_to 'Add', cm_admin.send(:"#{@model.name.underscore}_new_path"), class: 'btn-primary ml-2'
31
25
  - @model.available_actions.select{|act| act if act.route_type == 'collection'}.each do |custom_action|
32
26
  = custom_action_items(custom_action, 'index')
33
27
  - elsif @model.current_action.name == 'show'
@@ -36,4 +30,4 @@
36
30
 
37
31
  - edit_action = @model.available_actions.select{|act| act if act.action_type.eql?(:default) && act.name.eql?('edit')}
38
32
  - if edit_action.any? && policy([:cm_admin, @model.name.classify.constantize]).edit?
39
- = link_to "Edit #{@model.name.titleize.pluralize}", cm_admin.send(:"#{@model.name.underscore}_edit_path", @ar_object), class: 'primary-btn ml-2'
33
+ = link_to "Edit #{@model.name.titleize.pluralize}", cm_admin.send(:"#{@model.name.underscore}_edit_path", @ar_object), class: 'btn-primary ml-2'
@@ -1,8 +1,7 @@
1
1
  .show-page.cm-page-container
2
- .show-page__tabs.sticky-container.page-top-bar
3
- .cm-tabs-bar
4
- == render 'cm_admin/main/top_navbar'
5
- == render 'cm_admin/main/tabs'
2
+ .show-page__header.sticky-container.page-top-bar
3
+ == render 'cm_admin/main/top_navbar'
4
+ == render 'cm_admin/main/tabs'
6
5
  .show-page__inner.scrollable
7
6
  .history-box
8
7
  - @ar_object.action_trails.each do |at|
@@ -12,7 +12,7 @@
12
12
  p.success-msg Your file has been uploaded and it will be processed soon.
13
13
  / p.success-msg-info An email will be sent once the process is completed. If there are any problems with the import, we'll let you know through an email.
14
14
  .actions-wrapper
15
- a.secondary-btn href="#{cm_admin.send(:"#{@model.name.underscore}_import_path")}" Import new data
15
+ a.btn-secondary href="#{cm_admin.send(:"#{@model.name.underscore}_import_path")}" Import new data
16
16
  / button.cta-btn.ml-2 Back to Page_Name
17
17
  - else
18
18
  = simple_form_for(FileImport.new, url: "/admin/#{@model.ar_model.table_name}/import", method: :post, html: { class: "csv-import-form" }) do |f|
@@ -32,4 +32,4 @@
32
32
  li Add your data on the file without changing the format
33
33
  li Save the file as a csv
34
34
  li Upload the file in the field above
35
- = f.button :submit, class: "cta-btn import-btn", value: 'Import data'
35
+ = f.button :submit, class: "btn-cta", value: 'Import data'
@@ -16,4 +16,4 @@
16
16
  - @ar_object.errors.full_messages.each do |error_message|
17
17
  li = error_message
18
18
 
19
- = generate_form(@ar_object.class.name.constantize.new, @model)
19
+ = generate_form(@ar_object, @model)
@@ -1,8 +1,7 @@
1
1
  .show-page.cm-page-container
2
- .show-page__tabs.sticky-container.page-top-bar
3
- .cm-tabs-bar
4
- == render 'cm_admin/main/top_navbar'
5
- == render 'cm_admin/main/tabs'
2
+ .show-page__header.sticky-container.page-top-bar
3
+ == render 'cm_admin/main/top_navbar'
4
+ == render 'cm_admin/main/tabs'
6
5
  .show-page__inner.scrollable
7
6
  - if @action.partial
8
7
  == render @action.partial
@@ -1,9 +1,9 @@
1
1
  - if flash[:notice].present?
2
2
  javascript:
3
- $.jGrowl("#{flash[:notice]}", {theme: 'notice'})
3
+ $.jGrowl("#{flash[:notice]}", { theme: 'notice' })
4
4
  - elsif flash[:success].present?
5
5
  javascript:
6
- $.jGrowl("#{flash[:success]}", {theme: 'success'})
6
+ $.jGrowl("#{flash[:success]}", { theme: 'success' })
7
7
  - elsif flash[:alert].present?
8
8
  javascript:
9
- $.jGrowl("#{flash[:alert].html_safe}", {theme: 'error'})
9
+ $.jGrowl("#{flash[:alert].html_safe}", { theme: 'error' })
@@ -19,7 +19,7 @@
19
19
  span.move-arrow
20
20
  i.fa.fa-long-arrow-down
21
21
  span Select
22
- button.text-btn.enter-btn
22
+ p.enter-text
23
23
  | ENTER
24
- button.text-btn.open-btn
24
+ p.open-text
25
25
  | open
@@ -25,22 +25,20 @@ html
25
25
  .panel-area
26
26
  - if defined?(@action) && (@action&.layout_type.to_s == 'cm_association_show' || @action.parent == "show")
27
27
  .show-page.cm-page-container
28
- .show-page__tabs.sticky-container.page-top-bar
29
- .cm-tabs-bar
30
- == render 'cm_admin/main/top_navbar'
31
- == render 'cm_admin/main/tabs'
28
+ .show-page__header.sticky-container.page-top-bar
29
+ == render 'cm_admin/main/top_navbar'
30
+ == render 'cm_admin/main/tabs'
32
31
  .show-page__inner.scrollable
33
32
  = yield
34
33
  - elsif defined?(@action) && (@action&.layout_type.to_s == 'cm_association_index' || @action.parent == "index")
35
34
  .show-page.cm-page-container
36
- .show-page__tabs.sticky-container.page-top-bar
37
- .cm-tabs-bar
38
- == render 'cm_admin/main/top_navbar'
39
- - if @ar_object.model_name
40
- == render 'cm_admin/main/tabs'
41
- - if @associated_model && @associated_model.filters.present?
42
- .filters-bar
43
- == render partial: 'cm_admin/main/filters', locals: { filters: @associated_model.filters }
35
+ .show-page__header.sticky-container.page-top-bar
36
+ == render 'cm_admin/main/top_navbar'
37
+ - if @ar_object.model_name
38
+ == render 'cm_admin/main/tabs'
39
+ - if @associated_model && @associated_model.filters.present?
40
+ .filters-bar
41
+ == render partial: 'cm_admin/main/filters', locals: { filters: @associated_model.filters }
44
42
  = yield
45
43
  - else
46
44
  = yield
@@ -1,6 +1,10 @@
1
+ require_relative 'utils/helpers'
2
+
1
3
  module CmAdmin
2
4
  module Models
3
5
  class Filter
6
+ include Utils::Helpers
7
+
4
8
  attr_accessor :db_column_name, :filter_type, :placeholder, :collection
5
9
 
6
10
  VALID_FILTER_TYPES = Set[:date, :multi_select, :range, :search, :single_select].freeze
@@ -8,37 +12,55 @@ module CmAdmin
8
12
  def initialize(db_column_name:, filter_type:, options: {})
9
13
  raise TypeError, "Can't have array of multiple columns for #{filter_type} filter" if db_column_name.is_a?(Array) && db_column_name.size > 1 && !filter_type.to_sym.eql?(:search)
10
14
  raise ArgumentError, "Kindly select a valid filter type like #{VALID_FILTER_TYPES.sort.to_sentence(last_word_connector: ', or ')} instead of #{filter_type} for column #{db_column_name}" unless VALID_FILTER_TYPES.include?(filter_type.to_sym)
15
+
11
16
  @db_column_name, @filter_type = structure_data(db_column_name, filter_type)
17
+ set_default_values
12
18
  options.each do |key, value|
13
- self.send("#{key.to_s}=", value)
19
+ send("#{key}=", value)
14
20
  end
15
21
  end
16
22
 
17
23
  def structure_data(db_column_name, filter_type)
18
24
  filter_type = filter_type.is_a?(Array) ? filter_type[0].to_sym : filter_type.to_sym
19
25
 
20
- case filter_type
21
- when :search
22
- db_column_name = (Array.new << db_column_name).flatten.map{|x| x.class.eql?(Hash) ? x : x.to_sym}
23
- else
24
- db_column_name = db_column_name.is_a?(Array) ? db_column_name[0].to_sym : db_column_name.to_sym
25
- end
26
+ db_column_name = case filter_type
27
+ when :search
28
+ ([] << db_column_name).flatten.map { |x| x.instance_of?(Hash) ? x : x.to_sym }
29
+ else
30
+ db_column_name.is_a?(Array) ? db_column_name[0].to_sym : db_column_name.to_sym
31
+ end
26
32
  [db_column_name, filter_type]
27
33
  end
28
34
 
35
+ # Set default placeholder for the filter.
36
+ # Date and range filter will not have any placeholder.
37
+ # Else condition is added for fallback.
38
+ def set_default_values
39
+ placeholder = case filter_type
40
+ when :search
41
+ 'Search'
42
+ when :single_select, :multi_select
43
+ "Select/search #{humanized_field_value(db_column_name)}"
44
+ else
45
+ "Enter #{humanized_field_value(db_column_name)}"
46
+ end
47
+ self.placeholder = placeholder
48
+ end
49
+
29
50
  # Methods to filter the records based on the filter type.
30
51
  class << self
31
52
  def filtered_data(filter_params, records, filters)
32
53
  if filter_params
33
54
  filter_params.each do |scope_type, scope_value|
34
- scope_name = if scope_type.eql?('date') || scope_type.eql?('range')
35
- 'date_and_range'
36
- elsif scope_type.eql?('single_select') || scope_type.eql?('multi_select')
37
- 'dropdown'
38
- else
39
- scope_type
40
- end
41
- records = self.send("cm_#{scope_name}_filter", scope_value, records, filters) if scope_value.present?
55
+ scope_name = case scope_type
56
+ when 'date', 'range'
57
+ 'date_and_range'
58
+ when 'single_select', 'multi_select'
59
+ 'dropdown'
60
+ else
61
+ scope_type
62
+ end
63
+ records = send("cm_#{scope_name}_filter", scope_value, records, filters) if scope_value.present?
42
64
  end
43
65
  end
44
66
  records
@@ -46,15 +68,17 @@ module CmAdmin
46
68
 
47
69
  def cm_search_filter(scope_value, records, filters)
48
70
  return nil if scope_value.blank?
71
+
49
72
  table_name = records.table_name
50
- filters.select{|x| x if x.filter_type.eql?(:search)}.each do |filter|
73
+ filters.select { |x| x if x.filter_type.eql?(:search) }.each do |filter|
51
74
  query_variables = []
52
75
  filter.db_column_name.each do |col|
53
- if col.is_a?(Symbol)
76
+ case col
77
+ when Symbol
54
78
  query_variables << "#{table_name.pluralize}.#{col}"
55
- elsif col.is_a?(Hash)
79
+ when Hash
56
80
  col.map do |key, value|
57
- value.map {|val| query_variables << "#{key.to_s.pluralize}.#{val}" }
81
+ value.map { |val| query_variables << "#{key.to_s.pluralize}.#{val}" }
58
82
  end
59
83
  end
60
84
  end
@@ -62,14 +86,14 @@ module CmAdmin
62
86
  terms = terms.map { |e|
63
87
  (e.gsub('*', '%').prepend('%') + '%').gsub(/%+/, '%')
64
88
  }
65
- sql = ""
89
+ sql = ''
66
90
  query_variables.each.with_index do |column, i|
67
91
  sql.concat("#{column} ILIKE ?")
68
- sql.concat(' OR ') unless query_variables.size.eql?(i+1)
92
+ sql.concat(' OR ') unless query_variables.size.eql?(i + 1)
69
93
  end
70
94
 
71
- if filter.db_column_name.map{|x| x.is_a?(Hash)}.include?(true)
72
- associations_hash = filter.db_column_name.select{|x| x if x.is_a?(Hash)}.last
95
+ if filter.db_column_name.map { |x| x.is_a?(Hash) }.include?(true)
96
+ associations_hash = filter.db_column_name.select { |x| x if x.is_a?(Hash) }.last
73
97
  records = records.left_joins(associations_hash.keys).distinct
74
98
  end
75
99
 
@@ -85,19 +109,21 @@ module CmAdmin
85
109
 
86
110
  def cm_date_and_range_filter(scope_value, records, filters)
87
111
  return nil if scope_value.nil?
112
+
88
113
  scope_value.each do |key, value|
89
- if value.present?
90
- value = value.split(' to ')
91
- from = value[0].presence
92
- to = value[1].presence
93
- records = records.where(key => from..to)
94
- end
114
+ next unless value.present?
115
+
116
+ value = value.split(' to ')
117
+ from = value[0].presence
118
+ to = value[1].presence
119
+ records = records.where(key => from..to)
95
120
  end
96
121
  records
97
122
  end
98
123
 
99
124
  def cm_dropdown_filter(scope_value, records, filters)
100
125
  return nil if scope_value.nil?
126
+
101
127
  scope_value.each do |key, value|
102
128
  records = records.where(key => value) if value.present?
103
129
  end
@@ -1,6 +1,10 @@
1
+ require_relative 'utils/helpers'
2
+
1
3
  module CmAdmin
2
4
  module Models
3
5
  class FormField
6
+ include Utils::Helpers
7
+
4
8
  attr_accessor :field_name, :label, :header, :input_type, :collection, :disabled, :helper_method,
5
9
  :placeholder, :display_if, :html_attr, :target
6
10
 
@@ -13,9 +17,10 @@ module CmAdmin
13
17
  @field_name = field_name
14
18
  set_default_values
15
19
  attributes.each do |key, value|
16
- self.send("#{key.to_s}=", value)
20
+ send("#{key}=", value)
17
21
  end
18
- self.display_if = lambda { |arg| return true } if self.display_if.nil?
22
+ set_default_placeholder
23
+ self.display_if = lambda { |arg| return true } if display_if.nil?
19
24
  raise ArgumentError, "Kindly select a valid input type like #{VALID_INPUT_TYPES.sort.to_sentence(last_word_connector: ', or ')} instead of #{self.input_type} for form field #{field_name}" unless VALID_INPUT_TYPES.include?(self.input_type.to_sym)
20
25
  end
21
26
 
@@ -23,10 +28,20 @@ module CmAdmin
23
28
  self.disabled = false
24
29
  self.label = self.field_name.to_s.titleize
25
30
  self.input_type = :string
26
- self.placeholder = "Enter #{self.field_name.to_s.downcase.gsub('_', ' ')}"
27
31
  self.html_attr = {}
28
32
  self.target = {}
29
33
  end
34
+
35
+ def set_default_placeholder
36
+ return unless placeholder.nil?
37
+
38
+ self.placeholder = case input_type&.to_sym
39
+ when :single_select, :multi_select, :date, :date_time
40
+ "Select #{humanized_field_value(field_name)}"
41
+ else
42
+ "Enter #{humanized_field_value(field_name)}"
43
+ end
44
+ end
30
45
  end
31
46
  end
32
47
  end
@@ -0,0 +1,14 @@
1
+ module CmAdmin
2
+ module Models
3
+ module Utils
4
+ module Helpers
5
+ extend ActiveSupport::Concern
6
+
7
+ # Returns the humanized value of the field.
8
+ def humanized_field_value(name, capitalize: false)
9
+ name.to_s.humanize(capitalize: capitalize)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  module CmAdmin
2
- VERSION = '1.1.7'
2
+ VERSION = '1.1.9'
3
3
  end
@@ -169,7 +169,7 @@ module CmAdmin
169
169
  else
170
170
  value_mapped_text = value
171
171
  end
172
-
172
+
173
173
  concat(content_tag(:div, class: "position-relative mr-3 #{value ? '' : 'hidden'}") do
174
174
  concat filter_chip(value_mapped_text, filter)
175
175