cm-admin 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +12 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +6 -1
  6. data/Gemfile.lock +118 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +6 -40
  9. data/app/assets/images/logo.png +0 -0
  10. data/{lib/generators/cm_admin/templates/assets/stylesheets → app/assets/stylesheets/cm_admin}/base/auth.scss +16 -6
  11. data/app/assets/stylesheets/cm_admin/base/common.scss +237 -0
  12. data/app/assets/stylesheets/cm_admin/base/filters.scss +199 -0
  13. data/app/assets/stylesheets/cm_admin/base/form.scss +262 -0
  14. data/app/assets/stylesheets/cm_admin/base/main-nav.scss +47 -0
  15. data/app/assets/stylesheets/cm_admin/base/navbar.scss +67 -0
  16. data/app/assets/stylesheets/cm_admin/base/quicksearch.scss +69 -0
  17. data/app/assets/stylesheets/cm_admin/base/scaffold.scss +61 -0
  18. data/app/assets/stylesheets/cm_admin/base/show.scss +54 -0
  19. data/app/assets/stylesheets/cm_admin/base/sidebar.scss +225 -0
  20. data/app/assets/stylesheets/cm_admin/base/table.scss +303 -0
  21. data/app/assets/stylesheets/cm_admin/base/tabs.scss +26 -0
  22. data/app/assets/stylesheets/cm_admin/cm_admin.css.scss +26 -0
  23. data/app/assets/stylesheets/cm_admin/components/_alerts.scss +101 -0
  24. data/app/assets/stylesheets/cm_admin/components/_buttons.scss +135 -0
  25. data/app/assets/stylesheets/cm_admin/components/_dropdown-popup.scss +141 -0
  26. data/app/assets/stylesheets/cm_admin/components/_input.scss +274 -0
  27. data/app/assets/stylesheets/cm_admin/components/_modal.scss +34 -0
  28. data/app/assets/stylesheets/cm_admin/components/_range.scss +20 -0
  29. data/app/assets/stylesheets/cm_admin/components/_status-tag.scss +67 -0
  30. data/app/assets/stylesheets/cm_admin/components/index.scss +7 -0
  31. data/app/assets/stylesheets/cm_admin/dependency/bootstrap.min.css +7 -0
  32. data/app/assets/stylesheets/cm_admin/helpers/_mixins.scss +20 -0
  33. data/app/assets/stylesheets/cm_admin/helpers/_variable.scss +86 -0
  34. data/app/assets/stylesheets/cm_admin/helpers/index.scss +2 -0
  35. data/app/controllers/cm_admin/application_controller.rb +6 -0
  36. data/app/controllers/cm_admin/exports_controller.rb +16 -0
  37. data/app/controllers/cm_admin/main_controller.rb +8 -0
  38. data/app/helpers/cm_admin/application_helper.rb +11 -0
  39. data/app/javascript/packs/cm_admin/application.js +9 -0
  40. data/app/javascript/packs/cm_admin/filters.js +32 -0
  41. data/app/javascript/packs/cm_admin/scaffolds.js +14 -0
  42. data/app/views/cm_admin/main/_cm_pagy_nav.html.slim +23 -0
  43. data/app/views/cm_admin/main/_filters.html.slim +10 -0
  44. data/app/views/cm_admin/main/_table.html.slim +59 -0
  45. data/app/views/cm_admin/main/_top_navbar.html.slim +25 -0
  46. data/app/views/cm_admin/main/dashboard.html.slim +1 -0
  47. data/app/views/cm_admin/main/edit.html.slim +19 -0
  48. data/app/views/cm_admin/main/index.html.slim +9 -0
  49. data/app/views/cm_admin/main/new.html.slim +22 -0
  50. data/app/views/cm_admin/main/show.html.slim +13 -0
  51. data/app/views/layouts/_left_sidebar_nav.html.slim +30 -0
  52. data/app/views/layouts/cm_admin.html.slim +18 -0
  53. data/bin/console +1 -0
  54. data/bin/webpack +18 -0
  55. data/bin/webpack-dev-server +18 -0
  56. data/cm_admin.gemspec +20 -31
  57. data/{lib → config}/.DS_Store +0 -0
  58. data/config/initializers/active_record_extension.rb +9 -0
  59. data/config/routes.rb +18 -0
  60. data/config/webpack/development.js +5 -0
  61. data/config/webpack/environment.js +12 -0
  62. data/config/webpack/production.js +5 -0
  63. data/config/webpack/test.js +5 -0
  64. data/config/webpacker.yml +92 -0
  65. data/lib/c.png +0 -0
  66. data/lib/cm_admin.rb +31 -2
  67. data/lib/cm_admin/constants.rb +33 -0
  68. data/lib/cm_admin/engine.rb +38 -0
  69. data/lib/cm_admin/model.rb +262 -0
  70. data/lib/cm_admin/models/action.rb +22 -0
  71. data/lib/cm_admin/models/actions/blocks.rb +25 -0
  72. data/lib/cm_admin/models/blocks.rb +19 -0
  73. data/lib/cm_admin/models/column.rb +16 -0
  74. data/lib/cm_admin/models/export.rb +43 -0
  75. data/lib/cm_admin/models/field.rb +14 -0
  76. data/lib/cm_admin/models/filter.rb +30 -0
  77. data/lib/cm_admin/utils.rb +67 -0
  78. data/lib/cm_admin/version.rb +1 -1
  79. data/lib/cm_admin/view_helpers.rb +72 -0
  80. data/lib/cm_admin/view_helpers/field_column_helper.rb +23 -0
  81. data/lib/cm_admin/view_helpers/form_field_helper.rb +16 -0
  82. data/lib/cm_admin/view_helpers/form_helper.rb +55 -0
  83. data/lib/cm_admin/view_helpers/navigation_helper.rb +18 -0
  84. data/lib/cm_admin/view_helpers/page_info_helper.rb +21 -0
  85. data/lib/generators/cm_admin/install_generator.rb +10 -32
  86. data/lib/generators/cm_admin/templates/cm_admin_initializer.rb +4 -0
  87. data/lib/tasks/webpack_install.rake +63 -0
  88. data/package.json +18 -0
  89. data/postcss.config.js +12 -0
  90. data/yarn-error.log +44 -0
  91. data/yarn.lock +6903 -0
  92. metadata +123 -48
  93. data/CODE_OF_CONDUCT.md +0 -74
  94. data/lib/generators/cm_admin/USAGE +0 -8
  95. data/lib/generators/cm_admin/templates/assets/images/cm.png +0 -0
  96. data/lib/generators/cm_admin/templates/assets/stylesheets/application.css.scss +0 -33
  97. data/lib/generators/cm_admin/templates/assets/stylesheets/base/_variable.scss +0 -14
  98. data/lib/generators/cm_admin/templates/assets/stylesheets/base/form.scss +0 -125
  99. data/lib/generators/cm_admin/templates/assets/stylesheets/base/input-styles.scss +0 -72
  100. data/lib/generators/cm_admin/templates/assets/stylesheets/base/main-nav.scss +0 -79
  101. data/lib/generators/cm_admin/templates/assets/stylesheets/base/scaffold.scss +0 -95
  102. data/lib/generators/cm_admin/templates/assets/stylesheets/base/show.scss +0 -88
  103. data/lib/generators/cm_admin/templates/assets/stylesheets/base/sidebar.scss +0 -69
  104. data/lib/generators/cm_admin/templates/assets/stylesheets/base/table.scss +0 -246
  105. data/lib/generators/cm_admin/templates/layouts/_navbar.html.slim +0 -8
  106. data/lib/generators/cm_admin/templates/layouts/_side_navbar.html.slim +0 -12
  107. data/lib/generators/cm_admin/templates/layouts/application.html.slim +0 -20
  108. data/lib/generators/cm_admin/templates/layouts/initializer.rb +0 -2
  109. data/lib/generators/cm_admin/templates/views/_form.erb +0 -67
  110. data/lib/generators/cm_admin/templates/views/_table.erb +0 -22
  111. data/lib/generators/cm_admin/templates/views/edit.erb +0 -10
  112. data/lib/generators/cm_admin/templates/views/index.erb +0 -11
  113. data/lib/generators/cm_admin/templates/views/new.erb +0 -10
  114. data/lib/generators/cm_admin/templates/views/reset_password.erb +0 -12
  115. data/lib/generators/cm_admin/templates/views/show.erb +0 -18
  116. data/lib/generators/cm_admin/templates/views/sign_in.erb +0 -18
  117. data/lib/generators/cm_admin/view_generator.rb +0 -78
@@ -0,0 +1,33 @@
1
+ module CmAdmin
2
+ DEFAULT_ACTIONS = {
3
+ index: {
4
+ verb: :get,
5
+ path: '/'
6
+ },
7
+ new: {
8
+ verb: :get,
9
+ path: 'new'
10
+ },
11
+ show: {
12
+ verb: :get,
13
+ path: ':id'
14
+ },
15
+ create: {
16
+ verb: :post,
17
+ path: '/'
18
+ },
19
+ edit: {
20
+ verb: :get,
21
+ path: ':id/edit'
22
+ },
23
+ update: {
24
+ verb: :patch,
25
+ path: ':id'
26
+ },
27
+ destroy: {
28
+ verb: :delete,
29
+ path: ':id'
30
+ }
31
+ }
32
+ REJECTABLE_FIELDS = %w(id created_at updated_at)
33
+ end
@@ -0,0 +1,38 @@
1
+ require 'rails'
2
+ module CmAdmin
3
+ class Engine < Rails::Engine
4
+ isolate_namespace CmAdmin
5
+
6
+ config.app_middleware.use(
7
+ Rack::Static,
8
+ # note! this varies from the webpacker/engine documentation
9
+ urls: ["/cm-admin-packs"], root: CmAdmin::Engine.root.join("public")
10
+ )
11
+
12
+ initializer 'RailsAdmin precompile hook', group: :all do |app|
13
+ app.config.assets.precompile += %w(
14
+ cm_admin/cm_admin.css
15
+ )
16
+ end
17
+
18
+ initializer "webpacker.proxy" do |app|
19
+ insert_middleware = begin
20
+ CmAdmin.webpacker.config.dev_server.present?
21
+ rescue
22
+ nil
23
+ end
24
+ next unless insert_middleware
25
+
26
+ app.middleware.insert_before(
27
+ 0, Webpacker::DevServerProxy, # "Webpacker::DevServerProxy" if Rails version < 5
28
+ ssl_verify_none: true,
29
+ webpacker: CmAdmin.webpacker
30
+ )
31
+ end
32
+
33
+ def mount_path
34
+ CmAdmin::Engine.routes.find_script_name({})
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,262 @@
1
+ require_relative 'constants'
2
+ require_relative 'models/action'
3
+ require_relative 'models/field'
4
+ require_relative 'models/blocks'
5
+ require_relative 'models/column'
6
+ require_relative 'models/filter'
7
+ require_relative 'models/export'
8
+ require 'pagy'
9
+ require 'axlsx'
10
+
11
+
12
+ module CmAdmin
13
+ class Model
14
+ include Pagy::Backend
15
+ include Models::Blocks
16
+ attr_accessor :available_actions, :actions_set, :available_fields, :permitted_fields, :current_action, :params, :filters
17
+ attr_reader :name, :ar_model
18
+
19
+ # Class variable for storing all actions
20
+ # CmAdmin::Model.all_actions
21
+ singleton_class.send(:attr_accessor, :all_actions)
22
+
23
+ def initialize(entity, &block)
24
+ @name = entity.name
25
+ @ar_model = entity
26
+ @available_actions ||= []
27
+ @current_action = nil
28
+ @available_fields ||= {index: [], show: [], edit: [], new: []}
29
+ @params = nil
30
+ @filters ||= []
31
+ instance_eval(&block) if block_given?
32
+ actions unless @actions_set
33
+ $available_actions = @available_actions.dup
34
+ self.class.all_actions.push(@available_actions)
35
+ define_controller
36
+ end
37
+
38
+ class << self
39
+ def all_actions
40
+ @all_actions || []
41
+ end
42
+ end
43
+
44
+ # Insert into actions according to config block
45
+ def actions(only: [], except: [])
46
+ acts = CmAdmin::DEFAULT_ACTIONS.keys
47
+ acts = acts & (Array.new << only).flatten if only.present?
48
+ acts = acts - (Array.new << except).flatten if except.present?
49
+ acts.each do |act|
50
+ action_defaults = CmAdmin::DEFAULT_ACTIONS[act]
51
+ @available_actions << CmAdmin::Models::Action.new(name: act.to_s, verb: action_defaults[:verb], path: action_defaults[:path])
52
+ end
53
+ @actions_set = true
54
+ end
55
+
56
+ def cm_show(&block)
57
+ @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
58
+ puts "Top of the line"
59
+ yield
60
+ # action.instance_eval(&block)
61
+ puts "End of the line"
62
+ end
63
+
64
+ def cm_index(&block)
65
+ @current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
66
+ yield
67
+ # action.instance_eval(&block)
68
+ end
69
+
70
+ def cm_edit(&block)
71
+ action = CmAdmin::Models::Action.find_by(self, name: 'edit')
72
+ action.instance_eval(&block)
73
+ end
74
+
75
+ def show(params)
76
+ @current_action = CmAdmin::Models::Action.find_by(self, name: 'show')
77
+ @ar_object = @ar_model.find(params[:id])
78
+ end
79
+
80
+ def index(params)
81
+ @current_action = CmAdmin::Models::Action.find_by(self, name: 'index')
82
+ # Based on the params the filter and pagination object to be set
83
+ @ar_object = filter_by(params, filter_params=filter_params(params))
84
+ end
85
+
86
+ def filter_by(params, filter_params={}, sort_params={})
87
+ filtered_result = OpenStruct.new
88
+ sort_column = "users.created_at"
89
+ sort_direction = %w[asc desc].include?(sort_params[:sort_direction]) ? sort_params[:sort_direction] : "asc"
90
+ sort_params = {sort_column: sort_column, sort_direction: sort_direction}
91
+ final_data = filtered_data(filter_params)
92
+ pagy, records = pagy(final_data)
93
+ filtered_result.data = records
94
+ filtered_result.pagy = pagy
95
+ # filtered_result.facets = paginate(page, raw_data.size)
96
+ # filtered_result.sort = sort_params
97
+ # filtered_result.facets.sort = sort_params
98
+ return filtered_result
99
+ end
100
+
101
+ def filtered_data(filter_params)
102
+ records = self.name.constantize.where(nil)
103
+ if filter_params
104
+ filter_params.each do |scope, scope_value|
105
+ records = self.send("cm_#{scope}", scope_value, records)
106
+ end
107
+ end
108
+ records
109
+ end
110
+
111
+ def cm_search(scope_value, records)
112
+ return nil if scope_value.blank?
113
+ table_name = records.table_name
114
+
115
+ @filters.select{|x| x if x.filter_type.eql?(:search)}.each do |filter|
116
+ terms = scope_value.downcase.split(/\s+/)
117
+ terms = terms.map { |e|
118
+ (e.gsub('*', '%').prepend('%') + '%').gsub(/%+/, '%')
119
+ }
120
+ sql = ""
121
+ filter.db_column_name.each.with_index do |column, i|
122
+ sql.concat("#{table_name}.#{column} ILIKE ?")
123
+ sql.concat(' OR ') unless filter.db_column_name.size.eql?(i+1)
124
+ end
125
+
126
+ records = records.where(
127
+ terms.map { |term|
128
+ sql
129
+ }.join(' AND '),
130
+ *terms.map { |e| [e] * filter.db_column_name.size }.flatten
131
+ )
132
+ end
133
+ records
134
+ end
135
+
136
+ def new(params)
137
+ @ar_object = @ar_model.new
138
+ end
139
+
140
+ def edit(params)
141
+ @ar_object = @ar_model.find(params[:id])
142
+ end
143
+
144
+ def update(params)
145
+ @ar_object = @ar_model.find(params[:id])
146
+ @ar_object.update(resource_params(params))
147
+ end
148
+
149
+ def create(params)
150
+ @ar_object = @ar_model.new(resource_params(params))
151
+ end
152
+
153
+ def resource_params(params)
154
+ permittable_fields = @permitted_fields || @ar_model.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym)
155
+ params.require(self.name.underscore.to_sym).permit(*permittable_fields)
156
+ end
157
+
158
+ def page_title(title)
159
+ if @current_action
160
+ @current_action.page_title = title
161
+ end
162
+ end
163
+
164
+ def page_description(description)
165
+ if @current_action
166
+ @current_action.page_description = description
167
+ end
168
+ end
169
+
170
+ def field(field_name, options={})
171
+ puts "For printing field #{field_name}"
172
+ @available_fields[:show] << CmAdmin::Models::Field.new(field_name, options)
173
+ end
174
+
175
+ def column(field_name, options={})
176
+ unless @available_fields[:index].map{|x| x.db_column_name.to_sym}.include?(field_name)
177
+ puts "For printing column #{field_name}"
178
+ @available_fields[:index] << CmAdmin::Models::Column.new(field_name, options)
179
+ end
180
+ end
181
+
182
+ def all_db_columns(options={})
183
+ field_names = self.instance_variable_get(:@ar_model)&.columns&.map{|x| x.name.to_sym}
184
+ if options.include?(:exclude) && field_names
185
+ excluded_fields = (Array.new << options[:exclude]).flatten.map(&:to_sym)
186
+ field_names -= excluded_fields
187
+ end
188
+ field_names.each do |field_name|
189
+ column field_name
190
+ end
191
+ end
192
+
193
+ def self.find_by(search_hash)
194
+ CmAdmin.cm_admin_models.find { |x| x.name == search_hash[:name] }
195
+ end
196
+
197
+ # Custom actions
198
+ # eg
199
+ # class User < ApplicationRecord
200
+ # cm_admin do
201
+ # custom_action name: 'submit', verb: 'post', path: ':id/submit' do
202
+ # def user_submit
203
+ # Code for action here...
204
+ # end
205
+ # end
206
+ # end
207
+ # end
208
+ def custom_action(name: nil, verb: nil, layout: nil, partial: nil, path: nil, &block)
209
+ @available_actions << CmAdmin::Models::Action.new(name: name, verb: verb, layout: layout, partial: partial, path: path)
210
+ self.class.class_eval(&block)
211
+ end
212
+
213
+ def filter(db_column_name, filter_type, options={})
214
+ @filters << CmAdmin::Models::Filter.new(db_column_name: db_column_name, filter_type: filter_type, options: options)
215
+ end
216
+ private
217
+
218
+ # Controller defined for each model
219
+ # If model is User, controller will be UsersController
220
+ def define_controller
221
+ klass = Class.new(CmAdmin::ApplicationController) do
222
+
223
+ $available_actions.each do |action|
224
+ define_method action.name.to_sym do
225
+
226
+ # controller_name & action_name from ActionController
227
+ @model = CmAdmin::Model.find_by(name: controller_name.classify)
228
+ @model.params = params
229
+ @action = CmAdmin::Models::Action.find_by(@model, name: action_name)
230
+ @ar_object = @model.send(action_name, params)
231
+ respond_to do |format|
232
+ if %w(show index new edit).include?(action_name)
233
+ if request.xhr? && action_name.eql?('index')
234
+ format.html { render partial: '/cm_admin/main/table' }
235
+ else
236
+ format.html { render '/cm_admin/main/'+action_name }
237
+ end
238
+ elsif %w(create update destroy).include?(action_name)
239
+ if @ar_object.save
240
+ format.html { redirect_to CmAdmin::Engine.mount_path + "/#{@model.name.underscore.pluralize}" }
241
+ else
242
+ format.html { render '/cm_admin/main/new' }
243
+ end
244
+ elsif action.layout.present?
245
+ if action.partial.present?
246
+ render partial: action.partial, layout: action.layout
247
+ else
248
+ render layout: action.layout
249
+ end
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end if $available_actions.present?
255
+ CmAdmin.const_set "#{@name}Controller", klass
256
+ end
257
+
258
+ def filter_params(params)
259
+ params.require(:filters).permit(:search) if params[:filters]
260
+ end
261
+ end
262
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'actions/blocks'
2
+
3
+ module CmAdmin
4
+ module Models
5
+ class Action
6
+ include Actions::Blocks
7
+ attr_accessor :name, :verb, :layout, :partial, :path, :page_title, :page_description
8
+
9
+ def initialize(attributes = {})
10
+ attributes.each do |key, value|
11
+ self.send("#{key.to_s}=", value)
12
+ end
13
+ end
14
+
15
+ class << self
16
+ def find_by(model, search_hash)
17
+ model.available_actions.find { |i| i.name == search_hash[:name] }
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ module CmAdmin
2
+ module Models
3
+ module Actions
4
+ module Blocks
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ attr_accessor :title
9
+ end
10
+
11
+ def set_layout(name)
12
+ self.layout = name
13
+ end
14
+
15
+ def set_partial(name)
16
+ self.partial = name
17
+ end
18
+
19
+ def set_title(name)
20
+ self.title = name
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module CmAdmin
2
+ module Models
3
+ module Blocks
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ attr_accessor :menu, :title
8
+ end
9
+
10
+ def set_menu(state)
11
+ self.menu = state.to_s == 'on' ? true : false
12
+ end
13
+
14
+ def set_title(name)
15
+ self.title = name
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,16 @@
1
+ module CmAdmin
2
+ module Models
3
+ class Column
4
+ attr_accessor :db_column_name, :column_type, :header, :format, :prefix, :exportable
5
+
6
+ def initialize(db_column_name, attributes = {})
7
+ @db_column_name = db_column_name
8
+ attributes.each do |key, value|
9
+ self.send("#{key.to_s}=", value)
10
+ end
11
+ @exportable = true if attributes[:exportable].nil?
12
+ end
13
+
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ module CmAdmin
2
+ module Models
3
+ class Export
4
+ class << self
5
+ def generate_excel(klass_name, columns = [])
6
+ klass = klass_name.constantize
7
+ records = get_records(klass, columns)
8
+ file_path = "#{Rails.root}/tmp/#{klass}_data_#{DateTime.now.strftime("%Y-%m-%d_%H-%M-%S")}.xlsx"
9
+ create_workbook(records, columns, file_path)
10
+ return file_path
11
+ end
12
+
13
+ def get_records(klass, columns)
14
+ records = klass
15
+ deserialized_columns = CmAdmin::Utils.deserialize_csv_columns(columns, :as_json_params)
16
+ # This includes isn't recursve, a full solution should be recursive
17
+ records.includes(deserialized_columns[:include].keys).find_each.as_json(deserialized_columns)
18
+ end
19
+
20
+ def create_workbook(records, class_name, file_path)
21
+ flattened_records = records.map { |record| CmAdmin::Utils.flatten_hash(record) }
22
+ columns = flattened_records.map{|x| x.keys}.flatten.uniq.sort
23
+ size_arr = []
24
+ columns.size.times { size_arr << 22 }
25
+ xl = Axlsx::Package.new
26
+ xl.workbook.add_worksheet do |sheet|
27
+ sheet.add_row columns&.map(&:titleize), b: true
28
+ flattened_records.each do |record|
29
+ sheet.add_row(columns.map { |column| record[column] })
30
+ end
31
+ sheet.column_widths(*size_arr)
32
+ end
33
+ xl.serialize(file_path)
34
+ end
35
+
36
+ def exportable_columns(klass)
37
+ klass.available_fields[:index].map{|x| x.exportable ? x.db_column_name : ""}.reject { |c| c.empty? }
38
+ end
39
+
40
+ end
41
+ end
42
+ end
43
+ end