cm-admin 0.7.3 → 0.7.6
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +12 -8
- data/README.md +1 -1
- data/app/controllers/cm_admin/application_controller.rb +1 -2
- data/app/controllers/cm_admin/resource_controller.rb +194 -0
- data/app/javascript/packs/cm_admin/application.js +2 -0
- data/app/views/cm_admin/main/_actions_dropdown.html.slim +52 -0
- data/app/views/cm_admin/main/_associated_table.html.slim +2 -35
- data/app/views/cm_admin/main/_table.html.slim +3 -27
- data/cm_admin.gemspec +4 -3
- data/lib/cm_admin/model.rb +13 -67
- data/lib/cm_admin/models/action.rb +10 -0
- data/lib/cm_admin/version.rb +1 -1
- data/lib/cm_admin/view_helpers/action_dropdown_helper.rb +21 -0
- data/lib/cm_admin/view_helpers/field_display_helper.rb +2 -2
- data/lib/cm_admin/view_helpers/page_info_helper.rb +2 -0
- data/lib/cm_admin/view_helpers.rb +6 -3
- data/lib/generators/cm_admin/add_authentication_generator.rb +31 -0
- data/lib/generators/cm_admin/templates/application_controller.rb +8 -0
- data/lib/generators/cm_admin/templates/authentication.rb +14 -0
- data/lib/generators/cm_admin/templates/cm_admin_initializer.rb +2 -0
- data/lib/generators/cm_admin/templates/current.rb +9 -0
- data/package-lock.json +19910 -0
- data/package.json +1 -0
- data/yarn.lock +1164 -1147
- metadata +42 -21
- data/lib/cm_admin/models/controller_method.rb +0 -94
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d15eef9e06296f53028093dfc869ae0f0ecba8ba271bc3d39ef48e2f1bd09f16
|
4
|
+
data.tar.gz: 9ae45db5314a0187bf45a1f6864e97f18bfcb9de5cc32dc2ce1c5d388188e1b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31116fa28dcabfbbbfb404156e8aca01d2d3b12e04bfb82b08a8bf34520b416b4609167c43e921ff652f7ff1ef268b67df2f52f436fb08197062c0f91379b847
|
7
|
+
data.tar.gz: 3b1c8a5007cdb2d2d26a276ad77d261c99a354983c2ce782646c183093383e5526cb77cb027a89454bd1d2574dde61963a7adcd96b16dade5fcf194a4db4e0ab
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cm-admin (0.7.
|
4
|
+
cm-admin (0.7.6)
|
5
5
|
axlsx_rails (~> 0.6.1)
|
6
6
|
cocoon (~> 1.2.15)
|
7
|
+
local_time (~> 2.1.0)
|
7
8
|
pagy (~> 4.11.0)
|
8
9
|
pundit (~> 2.2.0)
|
9
10
|
slim (~> 4.1.0)
|
@@ -47,27 +48,30 @@ GEM
|
|
47
48
|
htmlentities (4.3.4)
|
48
49
|
i18n (1.10.0)
|
49
50
|
concurrent-ruby (~> 1.0)
|
50
|
-
|
51
|
+
local_time (2.1.0)
|
52
|
+
loofah (2.18.0)
|
51
53
|
crass (~> 1.0.2)
|
52
54
|
nokogiri (>= 1.5.9)
|
53
55
|
marcel (1.0.2)
|
54
56
|
method_source (1.0.0)
|
57
|
+
mini_portile2 (2.8.0)
|
55
58
|
minitest (5.15.0)
|
56
|
-
nokogiri (1.13.
|
59
|
+
nokogiri (1.13.6)
|
60
|
+
mini_portile2 (~> 2.8.0)
|
57
61
|
racc (~> 1.4)
|
58
62
|
pagy (4.11.0)
|
59
63
|
pundit (2.2.0)
|
60
64
|
activesupport (>= 3.0.0)
|
61
65
|
racc (1.6.0)
|
62
|
-
rack (2.2.
|
66
|
+
rack (2.2.4)
|
63
67
|
rack-proxy (0.7.2)
|
64
68
|
rack
|
65
|
-
rack-test (
|
66
|
-
rack (>= 1.
|
69
|
+
rack-test (2.0.2)
|
70
|
+
rack (>= 1.3)
|
67
71
|
rails-dom-testing (2.0.3)
|
68
72
|
activesupport (>= 4.2.0)
|
69
73
|
nokogiri (>= 1.6)
|
70
|
-
rails-html-sanitizer (1.4.
|
74
|
+
rails-html-sanitizer (1.4.3)
|
71
75
|
loofah (~> 2.3)
|
72
76
|
railties (7.0.2.3)
|
73
77
|
actionpack (= 7.0.2.3)
|
@@ -105,7 +109,7 @@ GEM
|
|
105
109
|
rack-proxy (>= 0.6.1)
|
106
110
|
railties (>= 5.2)
|
107
111
|
semantic_range (>= 2.3.0)
|
108
|
-
zeitwerk (2.
|
112
|
+
zeitwerk (2.6.0)
|
109
113
|
|
110
114
|
PLATFORMS
|
111
115
|
ruby
|
data/README.md
CHANGED
@@ -30,7 +30,7 @@ You can find more detailed documentation [here](https://github.com/commutatus/cm
|
|
30
30
|
|
31
31
|
## Demo
|
32
32
|
|
33
|
-
For demo check [here](http://cm-admin.labs.commutatus.com
|
33
|
+
For demo check [here](http://cm-admin.labs.commutatus.com)
|
34
34
|
For demo repo check [here](https://github.com/commutatus/cm-admin-panel-demo)
|
35
35
|
|
36
36
|
## Development
|
@@ -0,0 +1,194 @@
|
|
1
|
+
module CmAdmin
|
2
|
+
class ResourceController < ApplicationController
|
3
|
+
include Pundit::Authorization
|
4
|
+
include Pagy::Backend
|
5
|
+
|
6
|
+
helper CmAdmin::ViewHelpers
|
7
|
+
|
8
|
+
def cm_index(params)
|
9
|
+
@current_action = CmAdmin::Models::Action.find_by(@model, name: 'index')
|
10
|
+
# Based on the params the filter and pagination object to be set
|
11
|
+
@ar_object = filter_by(params, nil, @model.filter_params(params))
|
12
|
+
# resource_identifier
|
13
|
+
respond_to do |format|
|
14
|
+
if request.xhr?
|
15
|
+
format.html { render partial: '/cm_admin/main/table' }
|
16
|
+
else
|
17
|
+
format.html { render '/cm_admin/main/' + action_name }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def cm_show(params)
|
23
|
+
@current_action = CmAdmin::Models::Action.find_by(@model, name: 'show')
|
24
|
+
scoped_model = "CmAdmin::#{@model.name}Policy::Scope".constantize.new(Current.user, @model.name.constantize).resolve
|
25
|
+
@ar_object = scoped_model.find(params[:id])
|
26
|
+
resource_identifier
|
27
|
+
respond_to do |format|
|
28
|
+
format.html { render '/cm_admin/main/' + action_name }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def cm_new(params)
|
33
|
+
@current_action = CmAdmin::Models::Action.find_by(@model, name: 'new')
|
34
|
+
@ar_object = @model.ar_model.new
|
35
|
+
resource_identifier
|
36
|
+
respond_to do |format|
|
37
|
+
format.html { render '/cm_admin/main/' + action_name }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def cm_edit(params)
|
42
|
+
@current_action = CmAdmin::Models::Action.find_by(@model, name: 'edit')
|
43
|
+
@ar_object = @model.ar_model.name.classify.constantize.find(params[:id])
|
44
|
+
resource_identifier
|
45
|
+
respond_to do |format|
|
46
|
+
format.html { render '/cm_admin/main/' + action_name }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def cm_update(params)
|
51
|
+
@ar_object = @model.ar_model.name.classify.constantize.find(params[:id])
|
52
|
+
@ar_object.assign_attributes(resource_params(params))
|
53
|
+
resource_identifier
|
54
|
+
resource_responder
|
55
|
+
end
|
56
|
+
|
57
|
+
def cm_create(params)
|
58
|
+
@ar_object = @model.ar_model.name.classify.constantize.new(resource_params(params))
|
59
|
+
resource_identifier
|
60
|
+
resource_responder
|
61
|
+
end
|
62
|
+
|
63
|
+
def cm_destroy(params)
|
64
|
+
@ar_object = @model.ar_model.name.classify.constantize.find(params[:id])
|
65
|
+
respond_to do |format|
|
66
|
+
if @ar_object.destroy
|
67
|
+
format.html { redirect_back fallback_location: cm_admin.send("#{@model.name.underscore}_index_path"), notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is successful" }
|
68
|
+
else
|
69
|
+
format.html { redirect_back fallback_location: cm_admin.send("#{@model.name.underscore}_index_path"), notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is unsuccessful" }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def cm_custom_method(params)
|
75
|
+
scoped_model = "CmAdmin::#{@model.name}Policy::Scope".constantize.new(Current.user, @model.name.constantize).resolve
|
76
|
+
resource_identifier
|
77
|
+
respond_to do |format|
|
78
|
+
if @action.action_type == :custom
|
79
|
+
if @action.child_records
|
80
|
+
format.html { render @action.layout }
|
81
|
+
elsif @action.display_type == :page
|
82
|
+
data = @action.parent == "index" ? @ar_object.data : @ar_object
|
83
|
+
format.html { render @action.partial }
|
84
|
+
else
|
85
|
+
ar_object = @action.code_block.call(@ar_object)
|
86
|
+
if ar_object.errors.empty?
|
87
|
+
redirect_url = @model.current_action.redirection_url || @action.redirection_url || request.referrer || "/cm_admin/#{@model.ar_model.table_name}/#{@ar_object.id}"
|
88
|
+
format.html { redirect_to redirect_url, notice: "#{@action.name.titleize} is successful" }
|
89
|
+
else
|
90
|
+
error_messages = ar_object.errors.full_messages.map{|error_message| "<li>#{error_message}</li>"}.join
|
91
|
+
format.html { redirect_to request.referrer, alert: "<b>#{@action.name.titleize} is unsuccessful</b><br /><ul>#{error_messages}</ul>" }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def resource_identifier
|
99
|
+
@ar_object, @associated_model, @associated_ar_object = custom_controller_action(action_name, params.permit!) if !@ar_object.present? && params[:id].present?
|
100
|
+
authorize controller_name.classify.constantize, policy_class: "CmAdmin::#{controller_name.classify}Policy".constantize if defined? "CmAdmin::#{controller_name.classify}Policy".constantize
|
101
|
+
aar_model = request.url.split('/')[-2].classify.constantize if params[:aar_id]
|
102
|
+
@associated_ar_object = aar_model.find(params[:aar_id]) if params[:aar_id]
|
103
|
+
nested_tables = @model.available_fields[:new].except(:fields).keys
|
104
|
+
nested_tables += @model.available_fields[:edit].except(:fields).keys
|
105
|
+
@reflections = @model.ar_model.reflect_on_all_associations
|
106
|
+
nested_tables.each do |table_name|
|
107
|
+
reflection = @reflections.select {|x| x if x.name == table_name}.first
|
108
|
+
if reflection.macro == :has_many
|
109
|
+
@ar_object.send(table_name).build if action_name == "new" || action_name == "edit"
|
110
|
+
elsif action_name == "new"
|
111
|
+
@ar_object.send(('build_' + table_name.to_s).to_sym)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def resource_responder
|
117
|
+
respond_to do |format|
|
118
|
+
if params["referrer"]
|
119
|
+
redirect_url = params["referrer"]
|
120
|
+
else
|
121
|
+
redirect_url = CmAdmin::Engine.mount_path + "/#{@model.name.underscore.pluralize}/#{@ar_object.id}"
|
122
|
+
end
|
123
|
+
if @ar_object.save
|
124
|
+
format.html { redirect_to redirect_url, notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is successful" }
|
125
|
+
else
|
126
|
+
format.html { render '/cm_admin/main/new', notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is unsuccessful" }
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def custom_controller_action(action_name, params)
|
132
|
+
current_action = CmAdmin::Models::Action.find_by(@model, name: action_name.to_s)
|
133
|
+
if current_action
|
134
|
+
@current_action = current_action
|
135
|
+
@ar_object = @model.ar_model.name.classify.constantize.find(params[:id])
|
136
|
+
if @current_action.child_records
|
137
|
+
child_records = @ar_object.send(@current_action.child_records)
|
138
|
+
@associated_model = CmAdmin::Model.find_by(name: @model.ar_model.reflect_on_association(@current_action.child_records).klass.name)
|
139
|
+
if child_records.is_a? ActiveRecord::Relation
|
140
|
+
@associated_ar_object = filter_by(params, child_records)
|
141
|
+
else
|
142
|
+
@associated_ar_object = child_records
|
143
|
+
end
|
144
|
+
return @ar_object, @associated_model, @associated_ar_object
|
145
|
+
end
|
146
|
+
return @ar_object
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def filter_by(params, records, filter_params={}, sort_params={})
|
151
|
+
filtered_result = OpenStruct.new
|
152
|
+
sort_column = "created_at"
|
153
|
+
sort_direction = %w[asc desc].include?(sort_params[:sort_direction]) ? sort_params[:sort_direction] : "asc"
|
154
|
+
sort_params = {sort_column: sort_column, sort_direction: sort_direction}
|
155
|
+
|
156
|
+
records = "CmAdmin::#{@model.name}Policy::Scope".constantize.new(Current.user, @model.name.constantize).resolve if records.nil?
|
157
|
+
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)
|
160
|
+
pagy, records = pagy(final_data)
|
161
|
+
filtered_result.data = records
|
162
|
+
filtered_result.pagy = pagy
|
163
|
+
# filtered_result.facets = paginate(page, raw_data.size)
|
164
|
+
# filtered_result.sort = sort_params
|
165
|
+
# filtered_result.facets.sort = sort_params
|
166
|
+
return filtered_result
|
167
|
+
end
|
168
|
+
|
169
|
+
def resource_params(params)
|
170
|
+
permittable_fields = @permitted_fields || @model.ar_model.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym)
|
171
|
+
permittable_fields += @model.ar_model.name.constantize.reflect_on_all_associations.map {|x|
|
172
|
+
next if x.options[:polymorphic]
|
173
|
+
if x.class.name.include?('HasOne')
|
174
|
+
x.name.to_s.gsub('_attachment', '').gsub('rich_text_', '').to_sym
|
175
|
+
elsif x.class.name.include?('HasMany')
|
176
|
+
Hash[x.name.to_s.gsub('_attachment', ''), []]
|
177
|
+
end
|
178
|
+
}.compact
|
179
|
+
nested_tables = @model.available_fields[:new].except(:fields).keys
|
180
|
+
nested_tables += @model.available_fields[:edit].except(:fields).keys
|
181
|
+
nested_fields = nested_tables.uniq.map {|table|
|
182
|
+
Hash[
|
183
|
+
table.to_s + '_attributes',
|
184
|
+
table.to_s.classify.constantize.columns.map(&:name).reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }.map(&:to_sym) + [:id, :_destroy]
|
185
|
+
]
|
186
|
+
}
|
187
|
+
permittable_fields += nested_fields
|
188
|
+
@model.ar_model.columns.map { |col| permittable_fields << col.name.split('_cents') if col.name.include?('_cents') }
|
189
|
+
|
190
|
+
params.require(@model.name.underscore.to_sym).permit(*permittable_fields)
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
end
|
@@ -15,9 +15,11 @@ require('./filters.js')
|
|
15
15
|
require('./exports.js')
|
16
16
|
|
17
17
|
import jQuery from 'jquery'
|
18
|
+
import LocalTime from "local-time"
|
18
19
|
window.$ = jQuery
|
19
20
|
window.jQuery = jQuery
|
20
21
|
|
22
|
+
LocalTime.start()
|
21
23
|
require("@nathanvda/cocoon")
|
22
24
|
import "@fortawesome/fontawesome-free/css/all"
|
23
25
|
import "daterangepicker"
|
@@ -0,0 +1,52 @@
|
|
1
|
+
- edit_action = available_actions(cm_model, 'edit')
|
2
|
+
- destroy_action = available_actions(cm_model, 'destroy')
|
3
|
+
- custom_actions = available_actions(cm_model, 'custom_actions')
|
4
|
+
- custom_actions_modals = custom_actions.select{ |act| act if act.display_type.eql?(:modal) }
|
5
|
+
|
6
|
+
- if custom_actions.any? || edit_action.present? || destroy_action.present?
|
7
|
+
td.row-action-cell
|
8
|
+
.row-action-tool
|
9
|
+
button.secondary-btn.tool-btn
|
10
|
+
span
|
11
|
+
i.fa.fa-bars.bolder
|
12
|
+
span
|
13
|
+
i.fa.fa-angle-down
|
14
|
+
.popup-card.table-export-popup.hidden
|
15
|
+
- if edit_action.present?
|
16
|
+
= link_to "#{page_url('edit', ar_object)}" do
|
17
|
+
.popup-option
|
18
|
+
span
|
19
|
+
i.fa.fa-edit
|
20
|
+
| Edit
|
21
|
+
- if destroy_action.present?
|
22
|
+
= link_to "#{page_url('destroy', ar_object)}", method: :delete do
|
23
|
+
.popup-option
|
24
|
+
span
|
25
|
+
i.fa.fa-trash
|
26
|
+
| Destroy
|
27
|
+
- custom_actions.each do |custom_action|
|
28
|
+
- if custom_action.display_if.call(ar_object)
|
29
|
+
- case custom_action.display_type
|
30
|
+
- when :button
|
31
|
+
= link_to cm_admin.send("#{cm_model.name.underscore}_index_path") + '/' + custom_action.path.gsub(':id', ar_object.id.to_s), method: custom_action.verb do
|
32
|
+
.popup-option
|
33
|
+
span
|
34
|
+
i class="#{custom_action.icon_name}"
|
35
|
+
= custom_action.name.humanize
|
36
|
+
- when :modal
|
37
|
+
= link_to '', data: { bs_toggle: 'modal', bs_target: "##{custom_action.name.classify}Modal-#{ar_object.id.to_s}" } do
|
38
|
+
.popup-option
|
39
|
+
span
|
40
|
+
i class="#{custom_action.icon_name}"
|
41
|
+
= custom_action.name.humanize
|
42
|
+
|
43
|
+
- if custom_actions_modals.any?
|
44
|
+
- custom_actions_modals.each do |custom_action|
|
45
|
+
.modal.fade id="#{custom_action.name.classify}Modal-#{ar_object.id.to_s}" aria-hidden='true' aria-labelledby="#{custom_action.name.classify}ModalLabel" tabindex='1'
|
46
|
+
.modal-dialog
|
47
|
+
.modal-content
|
48
|
+
.modal-header
|
49
|
+
h5.modal-title id="#{custom_action.name.classify}ModalLabel" = custom_action.name.classify
|
50
|
+
button.btn-close aria-label='Close' data-bs-dismiss='modal'
|
51
|
+
.modal-body
|
52
|
+
= render partial: custom_action.partial, locals: { ar_object: ar_object }
|
@@ -36,43 +36,10 @@
|
|
36
36
|
a href="#{CmAdmin::Engine.mount_path}/#{@associated_model.name.tableize}/#{ar_object.id}" = show_field_value(ar_object, column)
|
37
37
|
- else
|
38
38
|
span class="#{column.cm_css_class}" = show_field_value(ar_object, column)
|
39
|
-
-
|
40
|
-
|
41
|
-
td.row-action-cell
|
42
|
-
.row-action-tool
|
43
|
-
button.secondary-btn.tool-btn type="button"
|
44
|
-
span
|
45
|
-
i.fa.fa-bars.bolder
|
46
|
-
span
|
47
|
-
i.fa.fa-angle-down
|
48
|
-
.popup-card.table-export-popup.hidden
|
49
|
-
// To be added once the associated model has edit actions
|
50
|
-
/ .popup-option
|
51
|
-
/ a href="#{page_url('edit', ar_object)}"
|
52
|
-
/ | Edit
|
53
|
-
- associated_model_actions.each do |custom_action|
|
54
|
-
- if custom_action.display_if.call(ar_object)
|
55
|
-
.popup-option
|
56
|
-
- if custom_action.display_type == :button
|
57
|
-
= link_to cm_admin.send("#{@associated_model.name.underscore}_index_path") + '/' + custom_action.path.gsub(':id', ar_object.id.to_s), method: custom_action.verb do
|
58
|
-
span
|
59
|
-
i class="#{custom_action.icon_name}"
|
60
|
-
= custom_action.name.humanize
|
61
|
-
- elsif custom_action.display_type == :modal
|
62
|
-
= link_to custom_action.name.humanize, '', data: { bs_toggle: 'modal', bs_target: "##{custom_action.name.classify}Modal-#{ar_object.id.to_s}" }
|
39
|
+
- if @associated_model
|
40
|
+
== render partial: 'cm_admin/main/actions_dropdown', locals: { cm_model: @associated_model, ar_object: ar_object }
|
63
41
|
|
64
42
|
.cm-pagination
|
65
43
|
.cm-pagination__lhs Showing #{@associated_ar_object.pagy.from} to #{@associated_ar_object.pagy.to} out of #{@associated_ar_object.pagy.count}
|
66
44
|
.cm-pagination__rhs
|
67
45
|
== render partial: 'cm_admin/main/cm_pagy_nav', locals: { pagy: @associated_ar_object.pagy }
|
68
|
-
|
69
|
-
- @associated_ar_object.data.each do |ar_object|
|
70
|
-
- @associated_model && @associated_model.available_actions.select{|act| act if (act.route_type == 'member' && act.display_type == :modal)}.each do |custom_action|
|
71
|
-
.modal.fade id="#{custom_action.name.classify}Modal-#{ar_object.id.to_s}" aria-hidden='true' aria-labelledby="#{custom_action.name.classify}ModalLabel" tabindex='1'
|
72
|
-
.modal-dialog
|
73
|
-
.modal-content
|
74
|
-
.modal-header
|
75
|
-
h5.modal-title id="#{custom_action.name.classify}ModalLabel" = custom_action.name.classify
|
76
|
-
button.btn-close aria-label='Close' data-bs-dismiss='modal'
|
77
|
-
.modal-body
|
78
|
-
= render partial: custom_action.partial, locals: { ar_object: ar_object }
|
@@ -31,33 +31,9 @@
|
|
31
31
|
- else
|
32
32
|
= show_field_value(ar_object, column)
|
33
33
|
- if column.field_type == :drawer
|
34
|
-
= render partial: column.drawer_partial, locals: { ar_object: ar_object}
|
35
|
-
|
36
|
-
|
37
|
-
- custom_actions = @model.available_actions.select{|act| act if act.route_type == 'member' && [:button, :modal].include?(act.display_type)}
|
38
|
-
- if custom_actions.any? || edit_action.any?
|
39
|
-
td.row-action-cell
|
40
|
-
.row-action-tool
|
41
|
-
button.secondary-btn.tool-btn type="button"
|
42
|
-
span
|
43
|
-
i.fa.fa-bars.bolder
|
44
|
-
span
|
45
|
-
i.fa.fa-angle-down
|
46
|
-
.popup-card.table-export-popup.hidden
|
47
|
-
- if edit_action.any? && policy([:cm_admin, @model.name.classify.constantize]).edit?
|
48
|
-
= link_to "#{page_url('edit', ar_object)}" do
|
49
|
-
.popup-option
|
50
|
-
span
|
51
|
-
i.fa.fa-edit
|
52
|
-
| Edit
|
53
|
-
- custom_actions.each do |custom_action|
|
54
|
-
- if custom_action.name.present? && has_valid_policy(@model.name, custom_action.name)
|
55
|
-
- if custom_action.display_if.call(ar_object)
|
56
|
-
= link_to cm_admin.send("#{@model.name.underscore}_index_path") + '/' + custom_action.path.gsub(':id', ar_object.id.to_s), method: custom_action.verb do
|
57
|
-
.popup-option
|
58
|
-
span
|
59
|
-
i class="#{custom_action.icon_name}"
|
60
|
-
= custom_action.name.humanize
|
34
|
+
= render partial: column.drawer_partial, locals: { ar_object: ar_object }
|
35
|
+
- if @model
|
36
|
+
== render partial: 'cm_admin/main/actions_dropdown', locals: { cm_model: @model, ar_object: ar_object }
|
61
37
|
|
62
38
|
.cm-pagination
|
63
39
|
.cm-pagination__lhs Showing #{@ar_object.pagy.from} to #{@ar_object.pagy.to} out of #{@ar_object.pagy.count}
|
data/cm_admin.gemspec
CHANGED
@@ -26,10 +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 'pagy', '~> 4.11.0'
|
30
|
-
spec.add_runtime_dependency 'slim', '~> 4.1.0'
|
31
|
-
spec.add_runtime_dependency 'webpacker', '~> 5.2.1'
|
32
29
|
spec.add_runtime_dependency 'axlsx_rails', '~> 0.6.1'
|
33
30
|
spec.add_runtime_dependency 'cocoon', '~> 1.2.15'
|
31
|
+
spec.add_runtime_dependency 'local_time', '~> 2.1.0'
|
32
|
+
spec.add_runtime_dependency 'pagy', '~> 4.11.0'
|
34
33
|
spec.add_runtime_dependency 'pundit', '~> 2.2.0'
|
34
|
+
spec.add_runtime_dependency 'slim', '~> 4.1.0'
|
35
|
+
spec.add_runtime_dependency 'webpacker', '~> 5.2.1'
|
35
36
|
end
|
data/lib/cm_admin/model.rb
CHANGED
@@ -10,18 +10,17 @@ require_relative 'models/export'
|
|
10
10
|
require_relative 'models/cm_show_section'
|
11
11
|
require_relative 'models/tab'
|
12
12
|
require_relative 'models/dsl_method'
|
13
|
-
require_relative 'models/controller_method'
|
14
13
|
require 'pagy'
|
15
14
|
require 'axlsx'
|
16
15
|
require 'cocoon'
|
17
16
|
require 'pundit'
|
17
|
+
require 'local_time'
|
18
18
|
|
19
19
|
module CmAdmin
|
20
20
|
class Model
|
21
21
|
include Pagy::Backend
|
22
22
|
include Models::Blocks
|
23
23
|
include Models::DslMethod
|
24
|
-
include Models::ControllerMethod
|
25
24
|
attr_accessor :available_actions, :actions_set, :available_fields, :permitted_fields,
|
26
25
|
:current_action, :params, :filters, :available_tabs, :icon_name
|
27
26
|
attr_reader :name, :ar_model, :is_visible_on_sidebar
|
@@ -89,12 +88,13 @@ module CmAdmin
|
|
89
88
|
@icon_name = name
|
90
89
|
end
|
91
90
|
|
91
|
+
# Shared between export controller and resource controller
|
92
92
|
def filter_params(params)
|
93
93
|
# OPTIMIZE: Need to check if we can permit the filter_params in a better way
|
94
|
-
date_columns =
|
95
|
-
range_columns =
|
96
|
-
single_select_columns =
|
97
|
-
multi_select_columns =
|
94
|
+
date_columns = self.filters.select{|x| x.filter_type.eql?(:date)}.map(&:db_column_name)
|
95
|
+
range_columns = self.filters.select{|x| x.filter_type.eql?(:range)}.map(&:db_column_name)
|
96
|
+
single_select_columns = self.filters.select{|x| x.filter_type.eql?(:single_select)}.map(&:db_column_name)
|
97
|
+
multi_select_columns = self.filters.select{|x| x.filter_type.eql?(:multi_select)}.map{|x| Hash["#{x.db_column_name}", []]}
|
98
98
|
|
99
99
|
params.require(:filters).permit(:search, date: date_columns, range: range_columns, single_select: single_select_columns, multi_select: multi_select_columns) if params[:filters]
|
100
100
|
end
|
@@ -104,7 +104,7 @@ module CmAdmin
|
|
104
104
|
# Controller defined for each model
|
105
105
|
# If model is User, controller will be UsersController
|
106
106
|
def define_controller
|
107
|
-
klass = Class.new(CmAdmin::
|
107
|
+
klass = Class.new(CmAdmin::ResourceController) do
|
108
108
|
include Pundit::Authorization
|
109
109
|
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
|
110
110
|
|
@@ -116,68 +116,14 @@ module CmAdmin
|
|
116
116
|
@model.params = params
|
117
117
|
@action = CmAdmin::Models::Action.find_by(@model, name: action_name)
|
118
118
|
@model.current_action = @action
|
119
|
-
|
120
|
-
@ar_object
|
121
|
-
authorize controller_name.classify.constantize, policy_class: "CmAdmin::#{controller_name.classify}Policy".constantize if defined? "CmAdmin::#{controller_name.classify}Policy".constantize
|
122
|
-
aar_model = request.url.split('/')[-2].classify.constantize if params[:aar_id]
|
123
|
-
@associated_ar_object = aar_model.find(params[:aar_id]) if params[:aar_id]
|
124
|
-
nested_tables = @model.available_fields[:new].except(:fields).keys
|
125
|
-
nested_tables += @model.available_fields[:edit].except(:fields).keys
|
126
|
-
@reflections = @model.ar_model.reflect_on_all_associations
|
127
|
-
nested_tables.each do |table_name|
|
128
|
-
reflection = @reflections.select {|x| x if x.name == table_name}.first
|
129
|
-
if reflection.macro == :has_many
|
130
|
-
@ar_object.send(table_name).build if action_name == "new" || action_name == "edit"
|
131
|
-
else
|
132
|
-
@ar_object.send(('build_' + table_name.to_s).to_sym) if action_name == "new"
|
133
|
-
end
|
134
|
-
end
|
135
|
-
respond_to do |format|
|
136
|
-
if %w(show index new edit).include?(action_name)
|
137
|
-
if request.xhr? && action_name.eql?('index')
|
138
|
-
format.html { render partial: '/cm_admin/main/table' }
|
139
|
-
else
|
140
|
-
format.html { render '/cm_admin/main/'+action_name }
|
141
|
-
end
|
142
|
-
elsif %w(create update destroy).include?(action_name)
|
143
|
-
if params["referrer"]
|
144
|
-
redirect_url = params["referrer"]
|
145
|
-
elsif %w(create update).include?(action_name)
|
146
|
-
redirect_url = CmAdmin::Engine.mount_path + "/#{@model.name.underscore.pluralize}/#{@ar_object.id}"
|
147
|
-
else
|
148
|
-
redirect_url = CmAdmin::Engine.mount_path + "/#{@model.name.underscore.pluralize}"
|
149
|
-
end
|
150
|
-
if @ar_object.save
|
151
|
-
format.html { redirect_to redirect_url, notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is successful" }
|
152
|
-
else
|
153
|
-
format.html { render '/cm_admin/main/new', notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is unsuccessful" }
|
154
|
-
end
|
155
|
-
elsif action.action_type == :custom
|
156
|
-
if action.child_records
|
157
|
-
format.html { render action.layout }
|
158
|
-
elsif action.display_type == :page
|
159
|
-
data = @action.parent == "index" ? @ar_object.data : @ar_object
|
160
|
-
format.html { render action.partial }
|
161
|
-
else
|
162
|
-
ar_object = @action.code_block.call(@ar_object)
|
163
|
-
if ar_object.errors.empty?
|
164
|
-
redirect_url = @model.current_action.redirection_url || @action.redirection_url || request.referrer || "/cm_admin/#{@model.ar_model.table_name}/#{@ar_object.id}"
|
165
|
-
format.html { redirect_to redirect_url, notice: "#{@action.name.titleize} is successful" }
|
166
|
-
else
|
167
|
-
error_messages = ar_object.errors.full_messages.map{|error_message| "<li>#{error_message}</li>"}.join
|
168
|
-
format.html { redirect_to request.referrer, alert: "<b>#{@action.name.titleize} is unsuccessful</b><br /><ul>#{error_messages}</ul>" }
|
169
|
-
end
|
170
|
-
end
|
171
|
-
elsif action.layout.present?
|
172
|
-
if request.xhr? && action.partial.present?
|
173
|
-
format.html { render partial: action.partial }
|
174
|
-
else
|
175
|
-
format.html { render action.layout }
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end
|
119
|
+
send(@action.controller_action_name, params)
|
120
|
+
# @ar_object = @model.try(@action.parent || action_name, params)
|
179
121
|
end
|
180
122
|
end
|
123
|
+
|
124
|
+
def pundit_user
|
125
|
+
Current.user
|
126
|
+
end
|
181
127
|
private
|
182
128
|
|
183
129
|
def user_not_authorized
|
@@ -43,6 +43,16 @@ module CmAdmin
|
|
43
43
|
self.partial = partial
|
44
44
|
end
|
45
45
|
|
46
|
+
def controller_action_name
|
47
|
+
if self.action_type == :custom
|
48
|
+
'cm_custom_method'
|
49
|
+
elsif self.parent
|
50
|
+
'cm_' + self.parent
|
51
|
+
else
|
52
|
+
'cm_' + name
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
46
56
|
class << self
|
47
57
|
def find_by(model, search_hash)
|
48
58
|
model.available_actions.find { |i| i.name == search_hash[:name] }
|
data/lib/cm_admin/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
module CmAdmin
|
2
|
+
module ViewHelpers
|
3
|
+
module ActionDropdownHelper
|
4
|
+
def available_actions(cm_model, action_type)
|
5
|
+
if action_type.eql?('custom_actions')
|
6
|
+
cm_model.available_actions.select {
|
7
|
+
|act| act if act.route_type.eql?('member') &&
|
8
|
+
[:button, :modal].include?(act.display_type) &&
|
9
|
+
act.name.present? &&
|
10
|
+
has_valid_policy(cm_model.name, act.name)
|
11
|
+
}
|
12
|
+
else
|
13
|
+
cm_model.available_actions.select {
|
14
|
+
|act| act if act.action_type.eql?(:default) &&
|
15
|
+
act.name.eql?(action_type)
|
16
|
+
} if has_valid_policy(cm_model.name, action_type)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module CmAdmin
|
2
2
|
module ViewHelpers
|
3
3
|
module FieldDisplayHelper
|
4
|
-
|
5
4
|
def show_field(ar_object, field)
|
6
5
|
content_tag(:div, class: "info-split") do
|
7
6
|
concat show_field_label(ar_object, field)
|
@@ -33,7 +32,8 @@ module CmAdmin
|
|
33
32
|
when :string
|
34
33
|
ar_object.send(field.field_name).to_s
|
35
34
|
when :datetime
|
36
|
-
|
35
|
+
self.extend LocalTimeHelper
|
36
|
+
local_time(ar_object.send(field.field_name).strftime(field.format || "%d/%m/%Y").to_s) if ar_object.send(field.field_name)
|
37
37
|
when :text
|
38
38
|
ar_object.send(field.field_name)
|
39
39
|
when :custom
|