cm-admin 0.7.6 → 0.7.8

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +6 -5
  3. data/Gemfile.lock +41 -20
  4. data/app/assets/stylesheets/cm_admin/base/table.scss +1 -1
  5. data/app/controllers/cm_admin/resource_controller.rb +7 -4
  6. data/app/javascript/packs/cm_admin/exports.js +0 -1
  7. data/app/views/cm_admin/main/_associated_table.html.slim +3 -0
  8. data/app/views/cm_admin/main/_table.html.slim +1 -1
  9. data/app/views/cm_admin/main/_tabs.html.slim +1 -1
  10. data/cm_admin.gemspec +2 -2
  11. data/lib/cm_admin/models/form_field.rb +1 -1
  12. data/lib/cm_admin/version.rb +1 -1
  13. data/lib/cm_admin/view_helpers/form_field_helper.rb +6 -4
  14. data/lib/cm_admin/view_helpers.rb +18 -18
  15. data/lib/generators/cm_admin/add_graphql_generator.rb +25 -0
  16. data/lib/generators/cm_admin/templates/concerns/attachable.rb +63 -0
  17. data/lib/generators/cm_admin/templates/concerns/filtered_list.rb +22 -0
  18. data/lib/generators/cm_admin/templates/concerns/paginator.rb +12 -0
  19. data/lib/generators/cm_admin/templates/constants.rb +3 -0
  20. data/lib/generators/cm_admin/templates/exceptions/base_exception.rb +9 -0
  21. data/lib/generators/cm_admin/templates/graphql/enums/base/sort_column.rb +7 -0
  22. data/lib/generators/cm_admin/templates/graphql/enums/base/sort_direction.rb +8 -0
  23. data/lib/generators/cm_admin/templates/graphql/graphql_schema.rb +55 -0
  24. data/lib/generators/cm_admin/templates/graphql/inputs/base/attachment.rb +15 -0
  25. data/lib/generators/cm_admin/templates/graphql/inputs/base/filter.rb +15 -0
  26. data/lib/generators/cm_admin/templates/graphql/inputs/base/paging.rb +15 -0
  27. data/lib/generators/cm_admin/templates/graphql/inputs/base/sort.rb +15 -0
  28. data/lib/generators/cm_admin/templates/graphql/mutations/base_mutation.rb +8 -0
  29. data/lib/generators/cm_admin/templates/graphql/objects/base/attachment_type.rb +31 -0
  30. data/lib/generators/cm_admin/templates/graphql/objects/base/paging_type.rb +9 -0
  31. data/lib/generators/cm_admin/templates/graphql/queries/base_query.rb +4 -0
  32. data/package-lock.json +1674 -1233
  33. data/package.json +2 -2
  34. data/tmp/cache/webpacker/last-compilation-digest-development +1 -1
  35. data/yarn.lock +393 -1331
  36. metadata +29 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d15eef9e06296f53028093dfc869ae0f0ecba8ba271bc3d39ef48e2f1bd09f16
4
- data.tar.gz: 9ae45db5314a0187bf45a1f6864e97f18bfcb9de5cc32dc2ce1c5d388188e1b1
3
+ metadata.gz: 2a03ed809475bd54b0365e020bb5d3ff1be6a2c16d2e2a2bf82b175af9ee26b8
4
+ data.tar.gz: 454ea27724b9f6e8c6297a81af181ce9e365fba0bbd777c68c9c1fdb6d5f47d0
5
5
  SHA512:
6
- metadata.gz: 31116fa28dcabfbbbfb404156e8aca01d2d3b12e04bfb82b08a8bf34520b416b4609167c43e921ff652f7ff1ef268b67df2f52f436fb08197062c0f91379b847
7
- data.tar.gz: 3b1c8a5007cdb2d2d26a276ad77d261c99a354983c2ce782646c183093383e5526cb77cb027a89454bd1d2574dde61963a7adcd96b16dade5fcf194a4db4e0ab
6
+ metadata.gz: f6b7f5d92c8e26d67b3587fe3c1e0b674bf3bb49aca01d958495f1093b369ab1993383eda2ae744587dea723a8534a7bc3d4d51ef94cd0f6c9aa35bc2186525a
7
+ data.tar.gz: 2ccc66f2c64f05e584a4a33da9b0117868272d039e984e8822a90c6957fa48c2654ca3f9ad8b1a2a631a87f50bcd2c761de5d84e4f50b30915b1ad24f2c291ec
data/Gemfile CHANGED
@@ -1,11 +1,12 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
- gem 'pagy', '~> 4.11.0'
4
- gem 'slim'
5
- gem "rake", "~> 12.0"
6
- gem "rspec", "~> 3.0"
7
3
  gem 'cocoon'
4
+ gem 'pagy', '~> 4.11.0'
8
5
  gem 'pundit'
6
+ gem 'rake', '~> 12.0'
7
+ gem 'rspec', '~> 3.0'
8
+ gem 'rubocop'
9
+ gem 'slim'
9
10
 
10
11
  # Specify your gem's dependencies in cm_admin.gemspec
11
12
  gemspec
data/Gemfile.lock CHANGED
@@ -1,52 +1,53 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cm-admin (0.7.6)
5
- axlsx_rails (~> 0.6.1)
4
+ cm-admin (0.7.7)
5
+ caxlsx_rails
6
6
  cocoon (~> 1.2.15)
7
7
  local_time (~> 2.1.0)
8
8
  pagy (~> 4.11.0)
9
9
  pundit (~> 2.2.0)
10
10
  slim (~> 4.1.0)
11
- webpacker (~> 5.2.1)
11
+ webpacker (~> 5.4.3)
12
12
 
13
13
  GEM
14
14
  remote: https://rubygems.org/
15
15
  specs:
16
- actionpack (7.0.2.3)
17
- actionview (= 7.0.2.3)
18
- activesupport (= 7.0.2.3)
16
+ actionpack (7.0.3.1)
17
+ actionview (= 7.0.3.1)
18
+ activesupport (= 7.0.3.1)
19
19
  rack (~> 2.0, >= 2.2.0)
20
20
  rack-test (>= 0.6.3)
21
21
  rails-dom-testing (~> 2.0)
22
22
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
23
- actionview (7.0.2.3)
24
- activesupport (= 7.0.2.3)
23
+ actionview (7.0.3.1)
24
+ activesupport (= 7.0.3.1)
25
25
  builder (~> 3.1)
26
26
  erubi (~> 1.4)
27
27
  rails-dom-testing (~> 2.0)
28
28
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
29
- activesupport (7.0.2.3)
29
+ activesupport (7.0.3.1)
30
30
  concurrent-ruby (~> 1.0, >= 1.0.2)
31
31
  i18n (>= 1.6, < 2)
32
32
  minitest (>= 5.1)
33
33
  tzinfo (~> 2.0)
34
- axlsx_rails (0.6.1)
35
- actionpack (>= 3.1)
36
- caxlsx (>= 3.0)
34
+ ast (2.4.2)
37
35
  builder (3.2.4)
38
36
  caxlsx (3.2.0)
39
37
  htmlentities (~> 4.3, >= 4.3.4)
40
38
  marcel (~> 1.0)
41
39
  nokogiri (~> 1.10, >= 1.10.4)
42
40
  rubyzip (>= 1.3.0, < 3)
41
+ caxlsx_rails (0.6.3)
42
+ actionpack (>= 3.1)
43
+ caxlsx (>= 3.0)
43
44
  cocoon (1.2.15)
44
- concurrent-ruby (1.1.9)
45
+ concurrent-ruby (1.1.10)
45
46
  crass (1.0.6)
46
47
  diff-lcs (1.4.4)
47
48
  erubi (1.10.0)
48
49
  htmlentities (4.3.4)
49
- i18n (1.10.0)
50
+ i18n (1.11.0)
50
51
  concurrent-ruby (~> 1.0)
51
52
  local_time (2.1.0)
52
53
  loofah (2.18.0)
@@ -55,11 +56,14 @@ GEM
55
56
  marcel (1.0.2)
56
57
  method_source (1.0.0)
57
58
  mini_portile2 (2.8.0)
58
- minitest (5.15.0)
59
- nokogiri (1.13.6)
59
+ minitest (5.16.2)
60
+ nokogiri (1.13.7)
60
61
  mini_portile2 (~> 2.8.0)
61
62
  racc (~> 1.4)
62
63
  pagy (4.11.0)
64
+ parallel (1.22.1)
65
+ parser (3.1.2.0)
66
+ ast (~> 2.4.1)
63
67
  pundit (2.2.0)
64
68
  activesupport (>= 3.0.0)
65
69
  racc (1.6.0)
@@ -73,14 +77,17 @@ GEM
73
77
  nokogiri (>= 1.6)
74
78
  rails-html-sanitizer (1.4.3)
75
79
  loofah (~> 2.3)
76
- railties (7.0.2.3)
77
- actionpack (= 7.0.2.3)
78
- activesupport (= 7.0.2.3)
80
+ railties (7.0.3.1)
81
+ actionpack (= 7.0.3.1)
82
+ activesupport (= 7.0.3.1)
79
83
  method_source
80
84
  rake (>= 12.2)
81
85
  thor (~> 1.0)
82
86
  zeitwerk (~> 2.5)
87
+ rainbow (3.1.1)
83
88
  rake (12.3.3)
89
+ regexp_parser (2.5.0)
90
+ rexml (3.2.5)
84
91
  rspec (3.10.0)
85
92
  rspec-core (~> 3.10.0)
86
93
  rspec-expectations (~> 3.10.0)
@@ -94,6 +101,18 @@ GEM
94
101
  diff-lcs (>= 1.2.0, < 2.0)
95
102
  rspec-support (~> 3.10.0)
96
103
  rspec-support (3.10.2)
104
+ rubocop (1.30.1)
105
+ parallel (~> 1.10)
106
+ parser (>= 3.1.0.0)
107
+ rainbow (>= 2.2.2, < 4.0)
108
+ regexp_parser (>= 1.8, < 3.0)
109
+ rexml (>= 3.2.5, < 4.0)
110
+ rubocop-ast (>= 1.18.0, < 2.0)
111
+ ruby-progressbar (~> 1.7)
112
+ unicode-display_width (>= 1.4.0, < 3.0)
113
+ rubocop-ast (1.18.0)
114
+ parser (>= 3.1.1.0)
115
+ ruby-progressbar (1.11.0)
97
116
  rubyzip (2.3.2)
98
117
  semantic_range (3.0.0)
99
118
  slim (4.1.0)
@@ -104,7 +123,8 @@ GEM
104
123
  tilt (2.0.10)
105
124
  tzinfo (2.0.4)
106
125
  concurrent-ruby (~> 1.0)
107
- webpacker (5.2.2)
126
+ unicode-display_width (2.1.0)
127
+ webpacker (5.4.3)
108
128
  activesupport (>= 5.2)
109
129
  rack-proxy (>= 0.6.1)
110
130
  railties (>= 5.2)
@@ -121,6 +141,7 @@ DEPENDENCIES
121
141
  pundit
122
142
  rake (~> 12.0)
123
143
  rspec (~> 3.0)
144
+ rubocop
124
145
  slim
125
146
 
126
147
  BUNDLED WITH
@@ -222,7 +222,7 @@
222
222
  width: calc(100% - 285px);
223
223
  left: 245px;
224
224
  background-color: #fff;
225
- z-index: 4;
225
+ z-index: 3;
226
226
  .table-sticky-top {
227
227
  position: sticky;
228
228
  top: 254px;
@@ -77,7 +77,11 @@ module CmAdmin
77
77
  respond_to do |format|
78
78
  if @action.action_type == :custom
79
79
  if @action.child_records
80
- format.html { render @action.layout }
80
+ if request.xhr?
81
+ format.html { render partial: '/cm_admin/main/associated_table' }
82
+ else
83
+ format.html { render @action.layout }
84
+ end
81
85
  elsif @action.display_type == :page
82
86
  data = @action.parent == "index" ? @ar_object.data : @ar_object
83
87
  format.html { render @action.partial }
@@ -137,7 +141,7 @@ module CmAdmin
137
141
  child_records = @ar_object.send(@current_action.child_records)
138
142
  @associated_model = CmAdmin::Model.find_by(name: @model.ar_model.reflect_on_association(@current_action.child_records).klass.name)
139
143
  if child_records.is_a? ActiveRecord::Relation
140
- @associated_ar_object = filter_by(params, child_records)
144
+ @associated_ar_object = filter_by(params, child_records, @associated_model.filter_params(params))
141
145
  else
142
146
  @associated_ar_object = child_records
143
147
  end
@@ -155,8 +159,7 @@ module CmAdmin
155
159
 
156
160
  records = "CmAdmin::#{@model.name}Policy::Scope".constantize.new(Current.user, @model.name.constantize).resolve if records.nil?
157
161
  records = records.order("#{@current_action.sort_column} #{@current_action.sort_direction}")
158
-
159
- final_data = CmAdmin::Models::Filter.filtered_data(filter_params, records, @model.filters)
162
+ final_data = CmAdmin::Models::Filter.filtered_data(filter_params, records, @associated_model ? @associated_model.filters : @model.filters)
160
163
  pagy, records = pagy(final_data)
161
164
  filtered_result.data = records
162
165
  filtered_result.pagy = pagy
@@ -1,6 +1,5 @@
1
1
  $(document).on('click', '.export-to-file-btn', function(e) {
2
2
  e.preventDefault();
3
3
  query_param = window.location.href.split("?")[1]
4
- $('#export-to-file-form').get(0).setAttribute('action', '/cm_admin/export_to_file.js?' + query_param);
5
4
  $("#export-to-file-form").submit();
6
5
  });
@@ -1,5 +1,8 @@
1
1
  .admin-table-index
2
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 }
3
6
  p.table-top__total-count = "#{@associated_ar_object.pagy.count} #{@action.child_records.to_s.gsub('_', ' ')} found"
4
7
  .table-top__column-action
5
8
  - if @associated_model && @associated_model.available_actions.map(&:name).include?('new')
@@ -27,7 +27,7 @@
27
27
  td.text-ellipsis
28
28
  span class="#{column.field_type.to_s} #{column.cm_css_class} "
29
29
  - if index == 0
30
- = link_to ar_object.send(column.field_name), "/cm_admin/#{ar_object.model_name.collection}/#{ar_object.id}"
30
+ = link_to ar_object.send(column.field_name), cm_admin.send("#{ar_object.model_name.singular}_show_path", ar_object.id)
31
31
  - else
32
32
  = show_field_value(ar_object, column)
33
33
  - if column.field_type == :drawer
@@ -4,4 +4,4 @@ ul.nav.nav-pills
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}?"))
5
5
  li.nav-item
6
6
  - nav_item_action_name = nav_item.custom_action.present? ? nav_item.custom_action : 'show'
7
- = link_to nav_item.nav_item_name.to_s.titleize, "/cm_admin/#{@model.name.underscore.pluralize}/#{@ar_object.id}/#{nav_item.custom_action}", class: "nav-link #{ nav_item_action_name == action_name ? 'active' : ''}"
7
+ = link_to nav_item.nav_item_name.to_s.titleize, cm_admin.send("#{@ar_object.model_name.singular}_#{nav_item_action_name}_path", @ar_object.id), class: "nav-link #{ nav_item_action_name == action_name ? 'active' : ''}"
data/cm_admin.gemspec CHANGED
@@ -26,11 +26,11 @@ Gem::Specification.new do |spec|
26
26
  spec.bindir = "exe"
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
- spec.add_runtime_dependency 'axlsx_rails', '~> 0.6.1'
29
+ spec.add_runtime_dependency 'caxlsx_rails'
30
30
  spec.add_runtime_dependency 'cocoon', '~> 1.2.15'
31
31
  spec.add_runtime_dependency 'local_time', '~> 2.1.0'
32
32
  spec.add_runtime_dependency 'pagy', '~> 4.11.0'
33
33
  spec.add_runtime_dependency 'pundit', '~> 2.2.0'
34
34
  spec.add_runtime_dependency 'slim', '~> 4.1.0'
35
- spec.add_runtime_dependency 'webpacker', '~> 5.2.1'
35
+ spec.add_runtime_dependency 'webpacker', '~> 5.4.3'
36
36
  end
@@ -1,7 +1,7 @@
1
1
  module CmAdmin
2
2
  module Models
3
3
  class FormField
4
- attr_accessor :field_name, :label, :header, :input_type, :collection, :custom_value, :disabled, :collection_method
4
+ attr_accessor :field_name, :label, :header, :input_type, :collection, :disabled, :helper_method
5
5
  VALID_INPUT_TYPES = [:integer, :decimal, :string, :single_select, :multi_select, :date, :date_time, :text, :single_file_upload, :multi_file_upload, :hidden, :rich_text].freeze
6
6
 
7
7
  def initialize(field_name, input_type, attributes = {})
@@ -1,3 +1,3 @@
1
1
  module CmAdmin
2
- VERSION = "0.7.6"
2
+ VERSION = "0.7.8"
3
3
  end
@@ -2,7 +2,7 @@ module CmAdmin
2
2
  module ViewHelpers
3
3
  module FormFieldHelper
4
4
  def input_field_for_column(f, field)
5
- value = field.custom_value || f.object.send(field.field_name)
5
+ value = field.helper_method ? send(field.helper_method) : f.object.send(field.field_name)
6
6
  is_required = f.object._validators[field.field_name].map(&:kind).include?(:presence)
7
7
  required_class = is_required ? 'required' : ''
8
8
  case field.input_type
@@ -29,13 +29,15 @@ module CmAdmin
29
29
  when :multi_file_upload
30
30
  return f.file_field field.field_name, multiple: true, class: "normal-input #{required_class}"
31
31
  when :hidden
32
- return f.hidden_field field.field_name, value: field.custom_value
32
+ return f.hidden_field field.field_name, value: value
33
33
  end
34
34
  end
35
35
 
36
+ # Refactor: Collection argument can be removed.
37
+ # helper_method argument will accept a method where value can be passed.
36
38
  def select_collection_value(field)
37
- if field.collection_method
38
- collection = send(field.collection_method)
39
+ if field.helper_method
40
+ collection = send(field.helper_method)
39
41
  elsif field.collection
40
42
  collection = field.collection
41
43
  else
@@ -1,6 +1,6 @@
1
1
  module CmAdmin
2
2
  module ViewHelpers
3
- Dir[File.expand_path("view_helpers", __dir__) + "/*.rb"].each { |f| require f }
3
+ Dir[File.expand_path('view_helpers', __dir__) + '/*.rb'].each { |f| require f }
4
4
 
5
5
  include ActionDropdownHelper
6
6
  include FieldDisplayHelper
@@ -14,17 +14,17 @@ module CmAdmin
14
14
  include ActionView::Helpers::FormTagHelper
15
15
  include ActionView::Helpers::TagHelper
16
16
 
17
- def exportable(klass, html_class: [])
18
- tag.a "Export as excel", class: html_class.append("filter-btn modal-btn mr-2"), data: {toggle: "modal", target: "#exportmodal"} do
17
+ def exportable(_klass, html_class: [])
18
+ tag.a 'Export as excel', class: html_class.append('filter-btn modal-btn mr-2'), data: { toggle: 'modal', target: '#exportmodal' } do
19
19
  concat tag.i class: 'fa fa-download'
20
- concat tag.span " Export"
20
+ concat tag.span ' Export'
21
21
  end
22
22
  end
23
23
 
24
24
  def column_pop_up(klass, required_filters = nil)
25
- tag.div class: "modal fade form-modal", id: "exportmodal", role: "dialog", aria: {labelledby: "exportModal"} do
26
- tag.div class: "modal-dialog modal-lg", role: "document" do
27
- tag.div class: "modal-content" do
25
+ tag.div class: 'modal fade form-modal', id: 'exportmodal', role: 'dialog', aria: { labelledby: 'exportModal' } do
26
+ tag.div class: 'modal-dialog modal-lg', role: 'document' do
27
+ tag.div class: 'modal-content' do
28
28
  concat pop_ups(klass, required_filters)
29
29
  end
30
30
  end
@@ -39,17 +39,17 @@ module CmAdmin
39
39
  end
40
40
 
41
41
  def pop_up_header
42
- tag.div class: "modal-header" do
43
- tag.button type: "button", class: "close", data: {dismiss: "modal"}, aria: {label: "Close"} do
44
- tag.span "X", aria: {hidden: "true"}
42
+ tag.div class: 'modal-header' do
43
+ tag.button type: 'button', class: 'close', data: { dismiss: 'modal' }, aria: { label: 'Close' } do
44
+ tag.span 'X', aria: { hidden: 'true' }
45
45
  end
46
- tag.h4 "Select columns to export", class: "modal-title", id: "exportModal"
46
+ tag.h4 'Select columns to export', class: 'modal-title', id: 'exportModal'
47
47
  end
48
48
  end
49
49
 
50
- def pop_up_body(klass, required_filters)
51
- tag.div class: "modal-body" do
52
- form_tag '/cm_admin/export_to_file.js', id: 'export-to-file-form', style: "width: 100%;", class:"cm-admin-csv-export-form" do
50
+ def pop_up_body(klass, _required_filters)
51
+ tag.div class: 'modal-body' do
52
+ form_tag cm_admin.send('export_to_file_path'), id: 'export-to-file-form', style: 'width: 100%;', class: 'cm-admin-csv-export-form' do
53
53
  concat hidden_field_tag 'class_name', klass.name.to_s, id: 'export-to-file-klass'
54
54
  concat checkbox_row(klass)
55
55
  concat tag.hr
@@ -59,7 +59,7 @@ module CmAdmin
59
59
  end
60
60
 
61
61
  def checkbox_row(klass)
62
- tag.div class: "row" do
62
+ tag.div class: 'row' do
63
63
  CmAdmin::Models::Export.exportable_columns(klass).each do |column_path|
64
64
  concat create_checkbox(column_path)
65
65
  end
@@ -67,9 +67,9 @@ module CmAdmin
67
67
  end
68
68
 
69
69
  def create_checkbox(column_path)
70
- tag.div class: "col-md-4" do
71
- concat check_box_tag "columns[]", column_path, id: column_path.to_s.gsub('/', '-')
72
- concat " " + column_path.to_s.gsub('/', '_').humanize
70
+ tag.div class: 'col-md-4' do
71
+ concat check_box_tag 'columns[]', column_path, id: column_path.to_s.gsub('/', '-')
72
+ concat " #{column_path.to_s.gsub('/', '_').humanize}"
73
73
  end
74
74
  end
75
75
  end
@@ -0,0 +1,25 @@
1
+ require 'rails/generators'
2
+
3
+ module CmAdmin
4
+ module Generators
5
+ class AddGraphqlGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
7
+
8
+ def add_graphql
9
+ gem 'graphql'
10
+ gem 'graphql-errors'
11
+ gem 'graphql-rails_logger'
12
+ generate 'graphql:install'
13
+ template 'graphql/graphql_schema.rb', "app/graphql/#{Rails.application.class.module_parent_name.underscore}_schema.rb"
14
+ directory 'graphql/inputs/base', 'app/graphql/types/inputs/base'
15
+ directory 'graphql/enums/base', 'app/graphql/types/enums/base'
16
+ directory 'graphql/objects/base', 'app/graphql/types/objects/base'
17
+ directory 'concerns', 'app/models/concerns'
18
+ copy_file 'graphql/mutations/base_mutation.rb', 'app/graphql/mutations/base_mutation.rb'
19
+ copy_file 'graphql/queries/base_query.rb', 'app/graphql/queries/base_query.rb'
20
+ copy_file 'exceptions/base_exception.rb', 'app/exceptions/base_exception.rb'
21
+ copy_file 'constants.rb', 'config/initializers/constants.rb'
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,63 @@
1
+ module Attachable
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ end
6
+
7
+ def save_with_attachments
8
+ save!
9
+ save_attachment
10
+ end
11
+
12
+ def update!(args)
13
+ add_accessors_for_attachment_types
14
+ super
15
+ save_attachment
16
+ end
17
+
18
+ def initialize(args)
19
+ add_accessors_for_attachment_types
20
+ super
21
+ end
22
+
23
+ def save_attachment
24
+ self.class.attachment_types.each do |attachment_type|
25
+ next if send("#{attachment_type}_file").blank?
26
+
27
+ arr = []
28
+ if send("#{attachment_type}_file").class.eql?(Array)
29
+ arr = send("#{attachment_type}_file")
30
+ else
31
+ arr << send("#{attachment_type}_file")
32
+ end
33
+ arr.each do |x|
34
+ regexp = %r{\Adata:([-\w]+\/[-\w\+\.]+)?;base64,(.*)}m
35
+ data_uri_parts = x[:content].match(regexp) || []
36
+ decoded_data = Base64.decode64(data_uri_parts[2])
37
+ filename = x[:filename]
38
+ filepath = "#{Rails.root}/tmp/#{filename}"
39
+ File.open(filepath, 'wb') do |f|
40
+ f.write(decoded_data)
41
+ end
42
+ send(attachment_type.to_s).attach(io: File.open(filepath), filename: filename, content_type: data_uri_parts[1])
43
+ File.delete(filepath)
44
+ end
45
+ end
46
+ end
47
+
48
+ def attached_url(attachment_type)
49
+ if send(attachment_type.to_s).attached? && send(attachment_type.to_s).class == ActiveStorage::Attached::One
50
+ Rails.application.routes.url_helpers.rails_blob_url(send(attachment_type.to_s))
51
+ elsif send(attachment_type.to_s).attached? && send(attachment_type.to_s).class == ActiveStorage::Attached::Many
52
+ send(attachment_type.to_s)
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def add_accessors_for_attachment_types
59
+ self.class.attachment_types.each do |attachment_type|
60
+ singleton_class.class_eval { attr_accessor "#{attachment_type}_file" }
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,22 @@
1
+ class FilteredList
2
+ attr_reader :data, :facets, :paging
3
+
4
+ def initialize(paginated_list)
5
+ self.data = paginated_list[:list]
6
+ self.paging = paginated_list
7
+ end
8
+
9
+ def data=(data)
10
+ @data = []
11
+ @data = data if data.present?
12
+ end
13
+
14
+ def paging=(paginated_list)
15
+ @paging = {
16
+ total_items: paginated_list[:list].total_count,
17
+ current_page: paginated_list[:list].current_page,
18
+ total_pages: paginated_list[:list].total_pages,
19
+ total_count: paginated_list[:total_count]
20
+ }
21
+ end
22
+ end
@@ -0,0 +1,12 @@
1
+ module Paginator
2
+ extend ActiveSupport::Concern
3
+ module ClassMethods
4
+ def list(per_page = DEFAULT_PER_PAGE, page = nil, _filter_params = nil, total_count = nil)
5
+ paginated_list = {}
6
+ per_page = DEFAULT_PER_PAGE if per_page == 0
7
+ paginated_list[:list] = self.page(page || 1).per(per_page)
8
+ paginated_list[:total_count] = total_count
9
+ FilteredList.new(paginated_list)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ DEFAULT_PER_PAGE = 20
2
+ DEFAULT_SORT_COLUMN = 'created_at'.freeze
3
+ DEFAULT_SORT_DIRECTION = 'desc'.freeze
@@ -0,0 +1,9 @@
1
+ class BaseException < StandardError
2
+ def initialize(message = nil)
3
+ @message = message
4
+ end
5
+
6
+ def message
7
+ @message || 'Hello!'
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ module Types
2
+ class Enums::Base::SortColumn < Types::BaseEnum
3
+ description 'Possible values for sort column'
4
+
5
+ value :created_at, 'Sort by created_at'
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Types
2
+ class Enums::Base::SortDirection < Types::BaseEnum
3
+ description 'Possible values for sort direction'
4
+
5
+ value :asc, 'Sort by ascending'
6
+ value :desc, 'Sort by descending'
7
+ end
8
+ end
@@ -0,0 +1,55 @@
1
+ class <%= Rails.application.class.module_parent_name %>Schema < GraphQL::Schema
2
+ mutation(Types::MutationType)
3
+ query(Types::QueryType)
4
+
5
+ # Union and Interface Resolution
6
+ def self.resolve_type(abstract_type, obj, ctx)
7
+ # TODO: Implement this function
8
+ # to return the correct object type for `obj`
9
+ raise(GraphQL::RequiredImplementationMissingError)
10
+ end
11
+
12
+ # Relay-style Object Identification:
13
+
14
+ # Return a string UUID for `object`
15
+ def self.id_from_object(object, type_definition, query_ctx)
16
+ # Here's a simple implementation which:
17
+ # - joins the type name & object.id
18
+ # - encodes it with base64:
19
+ # GraphQL::Schema::UniqueWithinType.encode(type_definition.name, object.id)
20
+ end
21
+
22
+ # Given a string UUID, find the object
23
+ def self.object_from_id(id, query_ctx)
24
+ # For example, to decode the UUIDs generated above:
25
+ # type_name, item_id = GraphQL::Schema::UniqueWithinType.decode(id)
26
+ #
27
+ # Then, based on `type_name` and `id`
28
+ # find an object in your application
29
+ # ...
30
+ end
31
+
32
+ rescue_from ActiveRecord::RecordNotFound do |err, obj, args, ctx, field|
33
+ GraphQL::ExecutionError.new("#{field.type.unwrap.graphql_name} not found", extensions: {code: :unprocessable_entity, sub_code: :record_invalid, message: err.message})
34
+ end
35
+
36
+ rescue_from ActiveRecord::RecordInvalid do |err, obj, args, ctx, field|
37
+ GraphQL::ExecutionError.new(err.message, extensions: {code: :unprocessable_entity, sub_code: :record_invalid, message: err.message})
38
+ end
39
+
40
+ rescue_from BaseException do |err, obj, args, ctx, field|
41
+ GraphQL::ExecutionError.new(err.message, extensions: {code: err.code, sub_code: err.sub_code, message: err.message})
42
+ end
43
+
44
+ unless Rails.env.development?
45
+ rescue_from StandardError do |err, obj, args, ctx, field|
46
+ rollbar_error = Rollbar.error(err)
47
+ GraphQL::ExecutionError.new("Internal Server Error", extensions: {code: :internal_server_error, uuid: rollbar_error[:uuid]})
48
+ end
49
+ end
50
+
51
+ def self.unauthorized_object(error)
52
+ raise Unauthorized, I18n.t("graphql.unauthorized", error_type: error.type.graphql_name)
53
+ end
54
+
55
+ end
@@ -0,0 +1,15 @@
1
+ module Types
2
+ module Inputs
3
+ module Base
4
+ class Attachment < Types::BaseInputObject
5
+ graphql_name 'AttachmentInput'
6
+
7
+ description 'Attributes needed to attach a file'
8
+
9
+ argument :filename, String, nil, required: true
10
+ argument :content, String, nil, required: true
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,15 @@
1
+ module Types
2
+ module Inputs
3
+ module Base
4
+ class Filter < Types::BaseInputObject
5
+ graphql_name 'BaseFilterInput'
6
+
7
+ description 'Attributes needed for filtering items'
8
+
9
+ argument :ids, [Integer], nil, required: false
10
+ argument :q, String, nil, required: false
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,15 @@
1
+ module Types
2
+ module Inputs
3
+ module Base
4
+ class Paging < Types::BaseInputObject
5
+ graphql_name 'PagingInput'
6
+
7
+ description 'Attributes needed for paginating list of items'
8
+
9
+ argument :page_no, Integer, nil, required: true
10
+ argument :per_page, Integer, nil, required: false
11
+ end
12
+ end
13
+ end
14
+ end
15
+