cm-admin 2.1.5 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/app/assets/javascripts/cm_admin/filters.js +30 -3
- data/app/assets/javascripts/cm_admin/scaffolds.js +0 -1
- data/app/assets/stylesheets/cm_admin/base/filters.scss +20 -0
- data/app/assets/stylesheets/cm_admin/cm_admin.css.scss +0 -1
- data/app/controllers/cm_admin/resource_controller.rb +58 -56
- data/app/views/cm_admin/main/_associated_table.html.slim +10 -12
- data/app/views/cm_admin/main/_nested_table_form.html.slim +1 -1
- data/app/views/cm_admin/main/_sort.html.slim +27 -0
- data/app/views/cm_admin/main/_table.html.slim +4 -5
- data/app/views/layouts/cm_admin.html.slim +1 -0
- data/config/importmap.rb +0 -1
- data/config/routes.rb +7 -1
- data/lib/cm_admin/model.rb +63 -60
- data/lib/cm_admin/models/dsl_method.rb +23 -0
- data/lib/cm_admin/version.rb +1 -1
- metadata +3 -3
- data/app/assets/stylesheets/cm_admin/dependency/fontawesome.all.css +0 -7831
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ab22f4bef2b77930d17a0910dbc5ee20f0773f9f025d7e7ba7fde8a55be7e5f8
|
4
|
+
data.tar.gz: ba334104c29113fbec5440dbe31b13b8fb8513efd6a8be7308928815141256a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67c7bf36f684d04d976fbad85a58f5910a84762f2e750918b3ab2eef6b7c9b4471bb9ff6f8b1594bb8dc7f3bf9910cf6b4560d9e80ad8ae24d6a8b56321901ae
|
7
|
+
data.tar.gz: 47b9d696e72e73ef748ffc51301891dc2fa3667f3f201ec61643167d13b286d0dc289ec7ddd4a867700c93a1b23bdbb5395b747d82e7fc71e00c39fc42e77e44
|
data/Gemfile.lock
CHANGED
@@ -19,6 +19,9 @@ var CmFilter = {
|
|
19
19
|
// Main method which will structure the existing filter values with the newly
|
20
20
|
// applied filter. Send and receive the value from the backend.
|
21
21
|
var getFilteredData = function(filterType, filterValue, filterColumn=null) {
|
22
|
+
let sortColumn = $('[data-behaviour="sort-column"]').val();
|
23
|
+
let sortDirection = $('[data-behaviour="sort-direction"]:checked').val();
|
24
|
+
|
22
25
|
var url = window.location.pathname
|
23
26
|
|
24
27
|
// Based on the value changed for recent filter generate the filterParams hash
|
@@ -27,15 +30,16 @@ var getFilteredData = function(filterType, filterValue, filterColumn=null) {
|
|
27
30
|
filterParams[filterType] = {};
|
28
31
|
filterParams[filterType][filterColumn] = filterValue
|
29
32
|
} else {
|
30
|
-
filterParams[filterType] = filterValue
|
33
|
+
if (filterType) filterParams[filterType] = filterValue
|
31
34
|
}
|
32
35
|
|
33
|
-
// TODO add sort params in the queryString
|
34
36
|
// page params is reinitialized to 1 when any new filter value is applied so
|
35
37
|
// that it won't throw the error when the user doesn't have sufficent data
|
36
38
|
// to display on the table.
|
37
39
|
var queryString = {
|
38
40
|
filters: filterParams,
|
41
|
+
sort_column: sortColumn,
|
42
|
+
sort_direction: sortDirection,
|
39
43
|
page: 1
|
40
44
|
};
|
41
45
|
|
@@ -346,4 +350,27 @@ $(document).on('click', '[data-behaviour="selected-chip"]', function(e) {
|
|
346
350
|
$(selectElement).parent().siblings(':first').addClass('search-area').removeClass('search-with-chips')
|
347
351
|
$(selectElement).parent().siblings(':last').removeClass('active')
|
348
352
|
}
|
349
|
-
})
|
353
|
+
})
|
354
|
+
|
355
|
+
$(document).on("change", '[data-behaviour="sort-column"], [data-behaviour="sort-direction"]', function (e) {
|
356
|
+
getFilteredData(null, null, null);
|
357
|
+
});
|
358
|
+
|
359
|
+
$(document).on("click", '[data-behaviour="reset-sort"]', function (e) {
|
360
|
+
let url = window.location.pathname;
|
361
|
+
let queryString = getParamsAsObject(window.location.search);
|
362
|
+
delete queryString["sort_column"];
|
363
|
+
delete queryString["sort_direction"];
|
364
|
+
let queryParam = jQuery.param(queryString);
|
365
|
+
$.ajax({
|
366
|
+
type: 'POST',
|
367
|
+
url: url + "/reset_sort_columns",
|
368
|
+
success: function(data) {
|
369
|
+
window.history.pushState("", "", url + "?" + queryParam);
|
370
|
+
window.location.reload();
|
371
|
+
},
|
372
|
+
error: function(jqxhr, textStatus, errorThrown) {
|
373
|
+
console.log(errorThrown, textStatus);
|
374
|
+
}
|
375
|
+
});
|
376
|
+
});
|
@@ -199,3 +199,23 @@
|
|
199
199
|
height: 31px;
|
200
200
|
}
|
201
201
|
}
|
202
|
+
|
203
|
+
.sort-button {
|
204
|
+
@extend .btn, .btn-outline-dark, .btn-sm, .d-flex;
|
205
|
+
gap: 4px;
|
206
|
+
}
|
207
|
+
|
208
|
+
.sort-menu {
|
209
|
+
padding: 0;
|
210
|
+
&__top {
|
211
|
+
@extend .p-3, .d-flex, .flex-column, .gap-3;
|
212
|
+
}
|
213
|
+
&__bottom {
|
214
|
+
@extend .d-flex, .px-3, .py-2, .bg-light, .rounded-2;
|
215
|
+
justify-content: center;
|
216
|
+
align-items: center;
|
217
|
+
button {
|
218
|
+
width: 100%;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
}
|
@@ -5,19 +5,21 @@ module CmAdmin
|
|
5
5
|
|
6
6
|
helper CmAdmin::ViewHelpers
|
7
7
|
|
8
|
+
skip_before_action :verify_authenticity_token, only: :reset_sort_columns
|
9
|
+
|
8
10
|
def cm_index(params)
|
9
11
|
@current_action = CmAdmin::Models::Action.find_by(@model, name: 'index')
|
10
12
|
# Based on the params the filter and pagination object to be set
|
11
13
|
authorize @ar_object, policy_class: "CmAdmin::#{controller_name.classify}Policy".constantize if defined? "CmAdmin::#{controller_name.classify}Policy".constantize
|
12
14
|
records = "CmAdmin::#{@model.name}Policy::IndexScope".constantize.new(Current.user, @model.name.constantize).resolve
|
13
15
|
records = apply_scopes(records)
|
14
|
-
if
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
16
|
+
@ar_object = if %w[table card].include?(params[:view_type]) || %i[table card].include?(@current_action.view_type)
|
17
|
+
filter_by(params, records, filter_params: @model.filter_params(params))
|
18
|
+
elsif (request.xhr? && params[:view_type] == 'kanban') || @current_action.view_type == :kanban
|
19
|
+
kanban_filter_by(params, records, @model.filter_params(params))
|
20
|
+
else
|
21
|
+
filter_by(params, records, filter_params: @model.filter_params(params))
|
22
|
+
end
|
21
23
|
respond_to do |format|
|
22
24
|
if request.xhr? && (params[:view_type] == 'kanban' || @current_action.view_type == :kanban)
|
23
25
|
format.json { render json: @ar_object }
|
@@ -45,7 +47,7 @@ module CmAdmin
|
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
48
|
-
def cm_new(
|
50
|
+
def cm_new(_params)
|
49
51
|
@current_action = CmAdmin::Models::Action.find_by(@model, name: 'new')
|
50
52
|
@ar_object = @model.ar_model.new
|
51
53
|
resource_identifier
|
@@ -91,19 +93,17 @@ module CmAdmin
|
|
91
93
|
end
|
92
94
|
|
93
95
|
def import
|
94
|
-
@model = Model.find_by({name: controller_name.classify})
|
95
|
-
allowed_params = params.permit(file_import: [
|
96
|
+
@model = Model.find_by({ name: controller_name.classify })
|
97
|
+
allowed_params = params.permit(file_import: %i[associated_model_name import_file]).to_h
|
96
98
|
file_import = ::FileImport.new(allowed_params[:file_import])
|
97
99
|
file_import.added_by = Current.user
|
98
100
|
respond_to do |format|
|
99
|
-
if file_import.save!
|
100
|
-
format.html { redirect_back fallback_location: cm_admin.send("#{@model.name.underscore}_index_path"), notice: "Your import is successfully queued." }
|
101
|
-
end
|
101
|
+
format.html { redirect_back fallback_location: cm_admin.send("#{@model.name.underscore}_index_path"), notice: 'Your import is successfully queued.' } if file_import.save!
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
105
|
def import_form
|
106
|
-
@model = Model.find_by({name: controller_name.classify})
|
106
|
+
@model = Model.find_by({ name: controller_name.classify })
|
107
107
|
respond_to do |format|
|
108
108
|
format.html { render '/cm_admin/main/import_form' }
|
109
109
|
end
|
@@ -116,9 +116,9 @@ module CmAdmin
|
|
116
116
|
if @bulk_action_processor.invalid_records.empty?
|
117
117
|
format.html { redirect_to request.referrer, notice: "#{@action.name.humanize} is successful" }
|
118
118
|
else
|
119
|
-
error_messages = @bulk_action_processor.invalid_records.map
|
119
|
+
error_messages = @bulk_action_processor.invalid_records.map do |invalid_record|
|
120
120
|
"<li>#{invalid_record.error_message}</li>"
|
121
|
-
|
121
|
+
end.join
|
122
122
|
format.html { redirect_to request.referrer, alert: "<b>#{@action.name.humanize} is unsuccessful</b><br /><ul>#{error_messages}</ul>" }
|
123
123
|
end
|
124
124
|
end
|
@@ -135,7 +135,7 @@ module CmAdmin
|
|
135
135
|
def cm_custom_method(params)
|
136
136
|
records = "CmAdmin::#{@model.name}Policy::#{@action.name.classify}Scope".constantize.new(Current.user, @model.name.constantize).resolve
|
137
137
|
@current_action = @action
|
138
|
-
if
|
138
|
+
if @action.parent == 'index'
|
139
139
|
records = apply_scopes(records)
|
140
140
|
@ar_object = filter_by(params, records, filter_params: @model.filter_params(params))
|
141
141
|
else
|
@@ -150,7 +150,7 @@ module CmAdmin
|
|
150
150
|
format.html { render @action.layout }
|
151
151
|
end
|
152
152
|
elsif @action.display_type == :page
|
153
|
-
|
153
|
+
@action.parent == 'index' ? @ar_object.data : @ar_object
|
154
154
|
# TODO: To set a default value for @action.layout, Since it is used in render above,
|
155
155
|
# Need to check and fix it.
|
156
156
|
format.html { render @action.partial, layout: @action.layout || 'cm_admin' }
|
@@ -163,11 +163,11 @@ module CmAdmin
|
|
163
163
|
redirect_url = @model.current_action.redirection_url || @action.redirection_url || request.referrer || "/cm_admin/#{@model.ar_model.table_name}/#{@response_object.id}"
|
164
164
|
format.html { redirect_to redirect_url, notice: "#{@action.name.titleize} is successful" }
|
165
165
|
else
|
166
|
-
error_messages = response_object.errors.full_messages.map{|error_message| "<li>#{error_message}</li>"}.join
|
166
|
+
error_messages = response_object.errors.full_messages.map { |error_message| "<li>#{error_message}</li>" }.join
|
167
167
|
format.html { redirect_to request.referrer, alert: "<b>#{@action.name.titleize} is unsuccessful</b><br /><ul>#{error_messages}</ul>" }
|
168
168
|
end
|
169
|
-
rescue =>
|
170
|
-
format.html { redirect_to request.referrer, alert: "<div><b>#{@action.name.titleize} is unsuccessful</b><br /><ul><li>#{
|
169
|
+
rescue StandardError => e
|
170
|
+
format.html { redirect_to request.referrer, alert: "<div><b>#{@action.name.titleize} is unsuccessful</b><br /><ul><li>#{e.message}</li></ul></div>" }
|
171
171
|
end
|
172
172
|
end
|
173
173
|
end
|
@@ -185,6 +185,12 @@ module CmAdmin
|
|
185
185
|
end
|
186
186
|
end
|
187
187
|
|
188
|
+
def reset_sort_columns
|
189
|
+
@model = Model.find_by({ name: controller_name.classify })
|
190
|
+
@model.default_sort_column = nil
|
191
|
+
@model.default_sort_direction = nil
|
192
|
+
end
|
193
|
+
|
188
194
|
def get_nested_table_fields(fields)
|
189
195
|
nested_table_fields = []
|
190
196
|
fields.each do |field|
|
@@ -200,17 +206,17 @@ module CmAdmin
|
|
200
206
|
def resource_identifier
|
201
207
|
@ar_object, @associated_model, @associated_ar_object = custom_controller_action(action_name, params.permit!) if !@ar_object.present? && params[:id].present?
|
202
208
|
authorize @ar_object, policy_class: "CmAdmin::#{controller_name.classify}Policy".constantize if defined? "CmAdmin::#{controller_name.classify}Policy".constantize
|
203
|
-
aar_model = request.url.split('/')[-2].classify.constantize
|
209
|
+
aar_model = request.url.split('/')[-2].classify.constantize if params[:aar_id]
|
204
210
|
@associated_ar_object = fetch_ar_object(aar_model, params[:aar_id]) if params[:aar_id]
|
205
211
|
nested_fields = get_nested_table_fields(@model.available_fields[:new])
|
206
212
|
nested_fields += get_nested_table_fields(@model.available_fields[:edit])
|
207
213
|
@reflections = @model.ar_model.reflect_on_all_associations
|
208
214
|
nested_fields.each do |nested_field|
|
209
215
|
table_name = nested_field.field_name
|
210
|
-
reflection = @reflections.select {|x| x if x.name == table_name}.first
|
216
|
+
reflection = @reflections.select { |x| x if x.name == table_name }.first
|
211
217
|
if reflection.macro == :has_many
|
212
|
-
@ar_object.send(table_name).build if action_name ==
|
213
|
-
elsif action_name ==
|
218
|
+
@ar_object.send(table_name).build if action_name == 'new' || action_name == 'edit'
|
219
|
+
elsif action_name == 'new'
|
214
220
|
@ar_object.send(('build_' + table_name.to_s).to_sym)
|
215
221
|
end
|
216
222
|
end
|
@@ -226,9 +232,7 @@ module CmAdmin
|
|
226
232
|
else
|
227
233
|
cm_admin.send("#{@model.name.underscore}_show_path", @ar_object)
|
228
234
|
end
|
229
|
-
if params['attachment_destroy_ids'].present?
|
230
|
-
ActiveStorage::Attachment.where(id: params['attachment_destroy_ids']).destroy_all
|
231
|
-
end
|
235
|
+
ActiveStorage::Attachment.where(id: params['attachment_destroy_ids']).destroy_all if params['attachment_destroy_ids'].present?
|
232
236
|
format.html { redirect_to redirect_url, allow_other_host: true, notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is successful" }
|
233
237
|
else
|
234
238
|
format.html { render '/cm_admin/main/new', notice: "#{action_name.titleize} #{@ar_object.class.name.downcase} is unsuccessful" }
|
@@ -259,7 +263,7 @@ module CmAdmin
|
|
259
263
|
else
|
260
264
|
child_records
|
261
265
|
end
|
262
|
-
|
266
|
+
[@ar_object, @associated_model, @associated_ar_object]
|
263
267
|
end
|
264
268
|
|
265
269
|
def apply_scopes(records)
|
@@ -272,35 +276,32 @@ module CmAdmin
|
|
272
276
|
def filter_by(params, records, parent_record: nil, filter_params: {}, sort_params: {})
|
273
277
|
filtered_result = OpenStruct.new
|
274
278
|
cm_model = @associated_model || @model
|
275
|
-
db_columns = cm_model.ar_model&.columns&.map{|x| x.name.to_sym}
|
276
|
-
if db_columns.include?(
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
279
|
+
db_columns = cm_model.ar_model&.columns&.map { |x| x.name.to_sym }
|
280
|
+
sort_column = if db_columns.include?(params[:sort_column]&.to_sym)
|
281
|
+
params[:sort_column]
|
282
|
+
else
|
283
|
+
cm_model.default_sort_column
|
284
|
+
end
|
285
|
+
sort_direction = params[:sort_direction] || cm_model.default_sort_direction
|
281
286
|
records = "CmAdmin::#{@model.name}Policy::#{@current_action.name.classify}Scope".constantize.new(Current.user, @model.name.constantize).resolve if records.nil?
|
282
|
-
records = records.order("#{sort_column} #{
|
287
|
+
records = records.order("#{sort_column} #{sort_direction}") if sort_column.present?
|
283
288
|
final_data = CmAdmin::Models::Filter.filtered_data(filter_params, records, cm_model.filters)
|
284
289
|
pagy, records = pagy(final_data)
|
285
290
|
filtered_result.data = records
|
286
291
|
filtered_result.pagy = pagy
|
287
292
|
filtered_result.parent_record = parent_record
|
288
293
|
filtered_result.associated_model = @associated_model.name if @associated_model
|
289
|
-
|
290
|
-
# filtered_result.facets = paginate(page, raw_data.size)
|
291
|
-
# filtered_result.sort = sort_params
|
292
|
-
# filtered_result.facets.sort = sort_params
|
293
|
-
return filtered_result
|
294
|
+
filtered_result
|
294
295
|
end
|
295
296
|
|
296
|
-
def kanban_filter_by(params, records, filter_params={},
|
297
|
+
def kanban_filter_by(params, records, filter_params = {}, _sort_params = {})
|
297
298
|
filtered_result = OpenStruct.new
|
298
299
|
cm_model = @associated_model || @model
|
299
|
-
db_columns = cm_model.ar_model&.columns&.map{|x| x.name.to_sym}
|
300
|
+
db_columns = cm_model.ar_model&.columns&.map { |x| x.name.to_sym }
|
300
301
|
if db_columns.include?(@current_action.sort_column)
|
301
|
-
|
302
|
+
@current_action.sort_column
|
302
303
|
else
|
303
|
-
|
304
|
+
'created_at'
|
304
305
|
end
|
305
306
|
records = "CmAdmin::#{@model.name}Policy::Scope".constantize.new(Current.user, @model.name.constantize).resolve if records.nil?
|
306
307
|
# records = records.order("#{sort_column} #{@current_action.sort_direction}")
|
@@ -313,7 +314,7 @@ module CmAdmin
|
|
313
314
|
page = params[:page] || 1
|
314
315
|
max_page = (group_record_count.values.max.to_i / per_page.to_f).ceil
|
315
316
|
filtered_result.paging['next_page'] = (page.to_i < max_page)
|
316
|
-
filtered_result.column_count = group_record_count.reject {|key,
|
317
|
+
filtered_result.column_count = group_record_count.reject { |key, _value| key.blank? }
|
317
318
|
|
318
319
|
column_names = @model.ar_model.send(params[:kanban_column_name]&.pluralize || @current_action.kanban_attr[:column_name].pluralize).keys
|
319
320
|
if @current_action.kanban_attr[:only].present?
|
@@ -326,8 +327,8 @@ module CmAdmin
|
|
326
327
|
filtered_result.data[column] = ''
|
327
328
|
next if page.to_i > (total_count.to_i / per_page.to_f).ceil
|
328
329
|
|
329
|
-
|
330
|
-
filtered_result.data[column] = render_to_string partial: 'cm_admin/main/kanban_card', locals: { ar_collection: records}
|
330
|
+
_, records = pagy(final_data.send(column), items: per_page.to_i)
|
331
|
+
filtered_result.data[column] = render_to_string partial: 'cm_admin/main/kanban_card', locals: { ar_collection: records }
|
331
332
|
end
|
332
333
|
filtered_result
|
333
334
|
end
|
@@ -340,8 +341,8 @@ module CmAdmin
|
|
340
341
|
table_name = @model.ar_model.reflections.with_indifferent_access[nested_table_field.field_name.to_s].klass.table_name
|
341
342
|
end
|
342
343
|
column_names = table_name.to_s.classify.constantize.column_names
|
343
|
-
column_names = column_names.map {|column_name| column_name.gsub('_cents', '') }
|
344
|
-
column_names = column_names.reject { |column_name| CmAdmin::REJECTABLE_FIELDS.include?(column_name) }.map(&:to_sym) + [
|
344
|
+
column_names = column_names.map { |column_name| column_name.gsub('_cents', '') }
|
345
|
+
column_names = column_names.reject { |column_name| CmAdmin::REJECTABLE_FIELDS.include?(column_name) }.map(&:to_sym) + %i[id _destroy]
|
345
346
|
if nested_table_field.associated_fields
|
346
347
|
nested_table_field.associated_fields.each do |associated_field|
|
347
348
|
column_names << generate_nested_params(associated_field)
|
@@ -355,17 +356,17 @@ module CmAdmin
|
|
355
356
|
end
|
356
357
|
|
357
358
|
def resource_params(params)
|
358
|
-
columns = @model.ar_model.columns_hash.map
|
359
|
+
columns = @model.ar_model.columns_hash.map do |_key, ar_adapter|
|
359
360
|
ar_adapter.sql_type_metadata.sql_type.ends_with?('[]') ? Hash[ar_adapter.name, []] : ar_adapter.name.to_sym
|
360
|
-
|
361
|
+
end
|
361
362
|
columns += @model.ar_model.stored_attributes.values.flatten
|
362
363
|
permittable_fields = @model.additional_permitted_fields + columns.reject { |i| CmAdmin::REJECTABLE_FIELDS.include?(i) }
|
363
364
|
permittable_fields += attachment_fields(@model.ar_model.name.constantize)
|
364
365
|
nested_table_fields = get_nested_table_fields(@model.available_fields[:new])
|
365
366
|
nested_table_fields += get_nested_table_fields(@model.available_fields[:edit])
|
366
|
-
nested_fields = nested_table_fields.uniq.map
|
367
|
+
nested_fields = nested_table_fields.uniq.map do |nested_table_field|
|
367
368
|
generate_nested_params(nested_table_field)
|
368
|
-
|
369
|
+
end
|
369
370
|
permittable_fields += nested_fields
|
370
371
|
@model.ar_model.columns.map { |col| permittable_fields << col.name.split('_cents') if col.name.include?('_cents') }
|
371
372
|
params.require(@model.name.underscore.to_sym).permit(*permittable_fields)
|
@@ -380,14 +381,15 @@ module CmAdmin
|
|
380
381
|
private
|
381
382
|
|
382
383
|
def attachment_fields(model_object)
|
383
|
-
model_object.reflect_on_all_associations.map
|
384
|
+
model_object.reflect_on_all_associations.map do |reflection|
|
384
385
|
next if reflection.options[:polymorphic]
|
386
|
+
|
385
387
|
if reflection.class.name.include?('HasOne')
|
386
388
|
reflection.name.to_s.gsub('_attachment', '').gsub('rich_text_', '').to_sym
|
387
389
|
elsif reflection.class.name.include?('HasMany')
|
388
390
|
Hash[reflection.name.to_s.gsub('_attachments', ''), []]
|
389
391
|
end
|
390
|
-
|
392
|
+
end.compact
|
391
393
|
end
|
392
394
|
end
|
393
395
|
end
|
@@ -3,18 +3,16 @@
|
|
3
3
|
.cm-index-page__filters
|
4
4
|
== render partial: 'cm_admin/main/filters', locals: { filters: @associated_model.filters }
|
5
5
|
p.table-top__total-count = "#{humanized_ar_collection_count(@associated_ar_object.pagy.count, @action.child_records.to_s)}"
|
6
|
-
.
|
7
|
-
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
/ span
|
17
|
-
/ i.fa.fa-angle-down
|
6
|
+
div.d-flex.gap-3
|
7
|
+
.table-top__column-action
|
8
|
+
- if @associated_model && @associated_model.available_actions.map(&:name).include?('new') && has_valid_policy(@associated_ar_object, 'new')
|
9
|
+
- association = @ar_object.class.reflect_on_all_associations.select{|x| x.name == @associated_model.name.tableize.to_sym }.first
|
10
|
+
- polymorphic_name = (association && association.inverse_of && association.inverse_of.options[:polymorphic]) ? association.inverse_of.name : ''
|
11
|
+
a href="#{CmAdmin::Engine.mount_path}/#{@associated_model.name.tableize}/new?associated_id=#{@ar_object.id}&associated_class=#{@ar_object.class.name.underscore}&polymorphic_name=#{polymorphic_name}&referrer=#{request.path}"
|
12
|
+
button.btn-secondary Add
|
13
|
+
- if @associated_model.sort_columns.present?
|
14
|
+
= render 'cm_admin/main/sort', model: @associated_model, ar_object: @associated_ar_object
|
15
|
+
|
18
16
|
- if flash[:alert].present?
|
19
17
|
.alert.alert-danger role="alert"
|
20
18
|
= flash[:alert].html_safe
|
@@ -13,7 +13,7 @@
|
|
13
13
|
- nested_table_field.fields.each do |field|
|
14
14
|
th data-field-type="#{field.input_type}"
|
15
15
|
- if field.label
|
16
|
-
= field.label.to_s
|
16
|
+
= field.label.to_s || field.field_name.to_s.titleize
|
17
17
|
tbody class="insert-cocoon-position-#{uniq_no}"
|
18
18
|
= f.fields_for table_name do |record|
|
19
19
|
- if record.object.persisted? || @ar_object.errors.present?
|
@@ -0,0 +1,27 @@
|
|
1
|
+
- sort_column = params[:sort_column] || model.default_sort_column
|
2
|
+
- sort_direction = params[:sort_direction] || model.default_sort_direction
|
3
|
+
.dropdown
|
4
|
+
button.sort-button data-bs-toggle="dropdown"
|
5
|
+
- if sort_column.present?
|
6
|
+
span
|
7
|
+
- if sort_direction == 'asc'
|
8
|
+
i.fa-duotone.fa-solid.fa-arrow-up-short-wide
|
9
|
+
- else
|
10
|
+
i.fa-duotone.fa-solid.fa-arrow-down-short-wide
|
11
|
+
= "#{model.sort_columns.find{ |c| c[:column] == sort_column }[:display_name]}"
|
12
|
+
- else
|
13
|
+
span
|
14
|
+
i.fa-solid.fa-arrow-down-arrow-up
|
15
|
+
| Sort
|
16
|
+
.dropdown-menu.sort-menu
|
17
|
+
div.sort-menu__top
|
18
|
+
= select_tag 'sort_column', options_for_select([['Select Column', '']] + model.sort_columns.map { |column| [column[:display_name], column[:column]] }, selected: sort_column), { class: 'form-select form-select-sm', data: { behaviour: 'sort-column' } }
|
19
|
+
.div.btn-group role="group"
|
20
|
+
input.btn-check type="radio" name="sort_direction" id="asc" value="asc" autocomplete="off" data-behaviour="sort-direction" checked=(sort_direction.blank? ? true : (sort_direction == 'asc' ? true : nil))
|
21
|
+
label.btn.btn-outline-dark.btn-sm for="asc" Ascending
|
22
|
+
|
23
|
+
input.btn-check type="radio" name="sort_direction" id="desc" value="desc" autocomplete="off" data-behaviour="sort-direction" checked=(sort_direction == 'desc' ? true : nil)
|
24
|
+
label.btn.btn-outline-dark.btn-sm for="desc" Descending
|
25
|
+
.sort-menu__bottom
|
26
|
+
button.btn.btn-sm.btn-ghost data-behaviour="reset-sort"
|
27
|
+
| Reset
|
@@ -7,11 +7,10 @@
|
|
7
7
|
i.fa.fa-table
|
8
8
|
a.btn.btn-ghost href="#{cm_admin.send("#{@model.name.underscore}_index_path")}?page=#{params[:page] || 1}&view_type=card"
|
9
9
|
i.fa.fa-table-cells
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
/ i.fa.fa-angle-down
|
10
|
+
|
11
|
+
- if @model.sort_columns.present?
|
12
|
+
= render 'cm_admin/main/sort', model: @model, ar_object: @ar_object
|
13
|
+
|
15
14
|
- if flash[:alert].present?
|
16
15
|
.alert.alert-danger.me-4 role="alert"
|
17
16
|
= flash[:alert].html_safe
|
@@ -29,6 +29,7 @@ html
|
|
29
29
|
= javascript_importmap_tags
|
30
30
|
= javascript_import_module_tag "cm_admin/application"
|
31
31
|
= javascript_include_tag 'cm_admin/custom', 'data-turbolinks-track': 'reload'
|
32
|
+
script src="https://kit.fontawesome.com/9c93dde7a7.js" data-mutate-approach="sync"
|
32
33
|
= stylesheet_link_tag 'cm_admin/custom', media: 'all', 'data-turbolinks-track': 'reload'
|
33
34
|
link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" /
|
34
35
|
|
data/config/importmap.rb
CHANGED
@@ -7,7 +7,6 @@ pin 'jgrowl', to: 'https://ga.jspm.io/npm:jgrowl@1.4.8/jquery.jgrowl.js'
|
|
7
7
|
pin 'moment', to: 'https://ga.jspm.io/npm:moment@2.29.4/moment.js'
|
8
8
|
pin 'trix', to: 'https://ga.jspm.io/npm:trix@2.1.3/dist/trix.esm.min.js'
|
9
9
|
pin '@rails/actiontext', to: 'https://ga.jspm.io/npm:@rails/actiontext@7.1.3-4/app/assets/javascripts/actiontext.esm.js'
|
10
|
-
pin '@fortawesome/fontawesome-free', to: 'https://ga.jspm.io/npm:@fortawesome/fontawesome-free@6.1.1/js/all.js'
|
11
10
|
pin 'daterangepicker', to: 'https://ga.jspm.io/npm:daterangepicker@3.1.0/daterangepicker.js'
|
12
11
|
pin '@nathanvda/cocoon', to: 'https://ga.jspm.io/npm:@nathanvda/cocoon@1.2.14/cocoon.js'
|
13
12
|
pin 'select2', to: 'https://ga.jspm.io/npm:select2@4.1.0-rc.0/dist/js/select2.js'
|
data/config/routes.rb
CHANGED
@@ -17,7 +17,13 @@ CmAdmin::Engine.routes.draw do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
model.
|
20
|
+
if model.sort_columns.present?
|
21
|
+
scope model.name.tableize do
|
22
|
+
send(:post, 'reset_sort_columns', to: "#{model.name.underscore}#reset_sort_columns", as: "#{model.name.underscore}_reset_sort_columns")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
model.available_actions.sort_by { |act| act.name }.each do |act|
|
21
27
|
scope model.name.tableize do
|
22
28
|
# Define route only when action trail related field is present
|
23
29
|
if act.name == 'history'
|