cm-admin 3.0.14 → 3.0.15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df3fadb7ab461116a44e122cd8ec236b43841f501c898cfea6faa4ca898ef982
4
- data.tar.gz: 2c4bc421eebb4ebd67242ae920f4e2d29170606525a72fc57f1807a3aa557e66
3
+ metadata.gz: a68921cd2290bc55a0fe8bad15e16cfdac64d9365756190a08c1e5ca45b35f57
4
+ data.tar.gz: 56639a3c550354da66a09cff791cd342fef7e276ca627ab76124c07b1c593ac8
5
5
  SHA512:
6
- metadata.gz: e8cb857fe0f0d2b673223a9b364b73b0049206dbeaa109f954db6cd483fa6873bafe66000ee2393311d881efa2dcd9d901003fad5766918013044f9bf4a65680
7
- data.tar.gz: 98bac5325e98387bacb6fc03be9dd880c74410c2bfd48d20eaf90784014c2eaa23393544a2564de2fad95bf0bb6e9716cbdcc4a7b271d5c4d6c8abdd0ae44a2d
6
+ metadata.gz: 3f11275fc5ddb6cd3793da121a5ea235b7f6ad0aba979edf3eb37d58800bf881ef55c43afd25e52cefc3b795b1feed6186c645f6a6fed6581cedc868a731e587
7
+ data.tar.gz: f99f2472c8682e4517210b86aa5ebda52e7134b4f2fcfca4aa3418fae7f42773644852cc1bfd6b1cb7a3392fb4907c05033c79f4c9587805d8428af80b592963
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cm-admin (3.0.14)
4
+ cm-admin (3.0.15)
5
5
  caxlsx_rails
6
6
  cocoon (~> 1.2.15)
7
7
  csv-importer (~> 0.8.2)
@@ -2,37 +2,45 @@ var currentRequest = null;
2
2
 
3
3
  var CmFilter = {
4
4
  // Generate or remove elements of the dropdown based on the search value.
5
- dropdown_search: function(element) {
6
- if(element.val()) {
5
+ dropdown_search: function (element) {
6
+ if (element.val()) {
7
7
  var filter = element.val().toUpperCase();
8
- var dropdownElements = element.parents(':nth(1)').find('.list-area').children();
8
+ var dropdownElements = element
9
+ .parents(":nth(1)")
10
+ .find(".list-area")
11
+ .children();
9
12
  for (var i = 0; i < dropdownElements.length; i++) {
10
13
  var txtValue = $(dropdownElements[i]).children().text();
11
14
  if (txtValue.toUpperCase().indexOf(filter) > -1) {
12
- $(dropdownElements[i]).css('display', 'flex');
15
+ $(dropdownElements[i]).css("display", "flex");
13
16
  } else {
14
- $(dropdownElements[i]).css('display', 'none');
17
+ $(dropdownElements[i]).css("display", "none");
15
18
  }
16
19
  }
17
20
  }
18
- }
19
- }
21
+ },
22
+ };
20
23
 
21
24
  // Main method which will structure the existing filter values with the newly
22
25
  // applied filter. Send and receive the value from the backend.
23
- var getFilteredData = function(filterType, filterValue, filterColumn=null, sortData=null) {
26
+ var getFilteredData = function (
27
+ filterType,
28
+ filterValue,
29
+ filterColumn = null,
30
+ sortData = null
31
+ ) {
24
32
  let sortColumn = $('[data-behaviour="sort-column"]').val();
25
33
  let sortDirection = $('[data-behaviour="sort-direction"]:checked').val();
26
34
 
27
- var url = window.location.pathname
35
+ var url = window.location.pathname;
28
36
 
29
37
  // Based on the value changed for recent filter generate the filterParams hash
30
38
  var filterParams = {};
31
39
  if (filterColumn) {
32
40
  filterParams[filterType] = {};
33
- filterParams[filterType][filterColumn] = filterValue
41
+ filterParams[filterType][filterColumn] = filterValue;
34
42
  } else {
35
- if (filterType) filterParams[filterType] = filterValue
43
+ if (filterType) filterParams[filterType] = filterValue;
36
44
  }
37
45
 
38
46
  // page params is reinitialized to 1 when any new filter value is applied so
@@ -42,139 +50,171 @@ var getFilteredData = function(filterType, filterValue, filterColumn=null, sortD
42
50
  filters: filterParams,
43
51
  sort_column: sortColumn,
44
52
  sort_direction: sortDirection,
45
- page: 1
53
+ page: 1,
46
54
  };
47
55
 
48
56
  // Generate the queryString by concatenating the filterParams and
49
57
  // searchParams that are already applied, if searchParams are present.
50
- var searchParams = window.location.search
51
- var searchParamsHash = getParamsAsObject(searchParams)
58
+ var searchParams = window.location.search;
59
+ var searchParamsHash = getParamsAsObject(searchParams);
52
60
  if (Object.keys(searchParamsHash).length > 0) {
53
61
  // Delete the previous applied value for multi_select filter from the
54
62
  // searchParams as altering the array with new and old value will create
55
63
  // more complicated logic. The new value is passed and structured in
56
64
  // filterParams and will be concadinated with the searchParams post deletion
57
- if (filterType == 'multi_select') {
58
- searchParams = getParamsAsObject(searchParams)
59
- if (searchParams['filters'] && searchParams['filters'][filterType] !== undefined) {
60
- delete(searchParams['filters'][filterType][filterColumn])
65
+ if (filterType == "multi_select") {
66
+ searchParams = getParamsAsObject(searchParams);
67
+ if (
68
+ searchParams["filters"] &&
69
+ searchParams["filters"][filterType] !== undefined
70
+ ) {
71
+ delete searchParams["filters"][filterType][filterColumn];
61
72
  }
62
- searchParams = jQuery.param(searchParams)
73
+ searchParams = jQuery.param(searchParams);
63
74
  }
64
- filterParams = jQuery.param(queryString)
65
- var availableParams = searchParams + '&' + filterParams
66
- var queryString = getParamsAsObject(availableParams)
75
+ filterParams = jQuery.param(queryString);
76
+ var availableParams = searchParams + "&" + filterParams;
77
+ var queryString = getParamsAsObject(availableParams);
67
78
  }
68
-
79
+
69
80
  if (filterColumn) {
70
81
  const filterChip = $(`[data-db-column="${filterColumn}"]`);
71
- const filterName = filterChip.find('.filter-name');
72
-
82
+ const filterName = filterChip.find(".filter-name");
83
+
73
84
  if (isValueEmpty(filterValue)) {
74
- if (!filterName.data('appended')) {
75
- filterName.html(`${filterName.text()} is `);
76
- filterName.data('appended', true);
77
- }
85
+ if (!filterName.data("appended")) {
86
+ filterName.html(`${filterName.text()} is `);
87
+ filterName.data("appended", true);
88
+ }
78
89
  } else {
79
- filterName.html(filterName.text().replace(/\s*is $/, ''));
80
- filterName.data('appended', false);
90
+ filterName.html(filterName.text().replace(/\s*is $/, ""));
91
+ filterName.data("appended", false);
81
92
  }
82
93
  }
83
94
 
84
- return currentRequest = $.ajax(url, {
85
- type: 'GET',
95
+ return (currentRequest = $.ajax(url, {
96
+ type: "GET",
86
97
  data: queryString,
87
- beforeSend: function() {
98
+ beforeSend: function () {
88
99
  if (currentRequest !== null) {
89
100
  currentRequest.abort();
90
101
  }
91
102
  },
92
- success: function(data) {
93
- var queryParam = jQuery.param(queryString)
94
- window.history.pushState("", "", url + '?' + queryParam);
95
- if ($('#view_type').val() == 'kanban') {
96
- $.each(data.table.data, function(key, value) {
97
- $('.' + key + ' .cards').html(value)
103
+ success: function (data) {
104
+ var queryParam = jQuery.param(queryString);
105
+ window.history.pushState("", "", url + "?" + queryParam);
106
+ if ($("#view_type").val() == "kanban") {
107
+ $.each(data.table.data, function (key, value) {
108
+ $("." + key + " .cards").html(value);
98
109
  });
99
- $('.kanban-list .counter').html(0)
100
- $.each(data.table.column_count, function(key, value) {
101
- $('.' + key + ' .counter').html(value)
110
+ $(".kanban-list .counter").html(0);
111
+ $.each(data.table.column_count, function (key, value) {
112
+ $("." + key + " .counter").html(value);
102
113
  });
103
114
  } else {
104
- $('.cm-index-page__table-container').html(data);
115
+ $(".cm-index-page__table-container").html(data);
105
116
  }
106
117
  if (sortData) {
107
- const dropdownElement = document.querySelector('[data-behaviour="sort-button-toggle"]');
118
+ const dropdownElement = document.querySelector(
119
+ '[data-behaviour="sort-button-toggle"]'
120
+ );
108
121
  if (dropdownElement) {
109
122
  const dropdown = new bootstrap.Dropdown(dropdownElement);
110
123
  dropdown.show();
111
124
  }
112
125
  }
113
126
  },
114
- error: function(jqxhr, textStatus, errorThrown) {
127
+ error: function (jqxhr, textStatus, errorThrown) {
115
128
  console.log(errorThrown, textStatus);
116
- }
117
- });
118
- }
129
+ },
130
+ }));
131
+ };
119
132
 
120
- const isValueEmpty = function(value) {
121
- return value !== undefined && value !== null && value !== '' && (!Array.isArray(value) || value.length !== 0);
122
- }
133
+ const isValueEmpty = function (value) {
134
+ return (
135
+ value !== undefined &&
136
+ value !== null &&
137
+ value !== "" &&
138
+ (!Array.isArray(value) || value.length !== 0)
139
+ );
140
+ };
123
141
 
124
- $(document).on('change', '[data-behaviour="filter"]', function(e) {
125
- var filterType = $(this).data('filter-type')
126
- var filterColumn = $(this).data('db-column')
142
+ $(document).on("change", '[data-behaviour="filter"]', function (e) {
143
+ var filterType = $(this).data("filter-type");
144
+ var filterColumn = $(this).data("db-column");
127
145
 
128
- if (filterType == 'range') {
129
- var rangeElements = $(this).parent().children()
130
- var filterValue = $(rangeElements[0]).val() + ' to ' + $(rangeElements[1]).val()
146
+ if (filterType == "range") {
147
+ var rangeElements = $(this).parent().children();
148
+ var filterValue =
149
+ $(rangeElements[0]).val() + " to " + $(rangeElements[1]).val();
131
150
  } else {
132
- var filterValue = $(this).val()
151
+ var filterValue = $(this).val();
133
152
  }
134
153
 
135
- $(this).parents(':nth(1)').children(':first').children(':nth(1)').text(filterValue)
136
- $(this).parents(':nth(1)').children(':first').children(':last').removeClass('hidden')
154
+ $(this)
155
+ .parents(":nth(1)")
156
+ .children(":first")
157
+ .children(":nth(1)")
158
+ .text(filterValue);
159
+ $(this)
160
+ .parents(":nth(1)")
161
+ .children(":first")
162
+ .children(":last")
163
+ .removeClass("hidden");
137
164
 
138
- unhideClearFilterBtn(filterValue)
139
- getFilteredData(filterType, filterValue, filterColumn)
165
+ unhideClearFilterBtn(filterValue);
166
+ getFilteredData(filterType, filterValue, filterColumn);
140
167
  });
141
168
 
142
- $(document).on('keyup', '[data-behaviour="input-search"]', function(e) {
169
+ $(document).on("keyup", '[data-behaviour="input-search"]', function (e) {
143
170
  e.stopPropagation();
144
171
 
145
172
  var searchValue = $(this).val();
146
- unhideClearFilterBtn(searchValue)
147
- getFilteredData('search', searchValue)
173
+ unhideClearFilterBtn(searchValue);
174
+ getFilteredData("search", searchValue);
148
175
  });
149
176
 
150
- $(document).on('click', '[data-behaviour="filter-option"]', function(e) {
151
- var filterType = $(this).data('filter-type')
152
- var filterColumn = $(this).data('db-column')
177
+ $(document).on("click", '[data-behaviour="filter-option"]', function (e) {
178
+ var filterType = $(this).data("filter-type");
179
+ var filterColumn = $(this).data("db-column");
153
180
 
154
181
  // Clear the search value post selection and regenerate the dropdown elements.
155
- var searchInputElement = $(this).parents(':nth(1)').children(':first').children()
156
- searchInputElement.val('')
157
- CmFilter.dropdown_search(searchInputElement)
158
-
159
- unhideFilter(filterType, filterColumn)
182
+ var searchInputElement = $(this)
183
+ .parents(":nth(1)")
184
+ .children(":first")
185
+ .children();
186
+ searchInputElement.val("");
187
+ CmFilter.dropdown_search(searchInputElement);
188
+
189
+ unhideFilter(filterType, filterColumn);
160
190
  });
161
191
 
162
- var unhideFilter = function(filterType, filterColumn) {
163
- var filterInputElement = $('[data-behaviour="filter-input"][data-filter-type=' + filterType + '][data-db-column='+ filterColumn + ']')
164
-
165
- filterInputElement.parent().removeClass('hidden');
166
- filterInputElement.click()
192
+ var unhideFilter = function (filterType, filterColumn) {
193
+ var filterInputElement = $(
194
+ '[data-behaviour="filter-input"][data-filter-type=' +
195
+ filterType +
196
+ "][data-db-column=" +
197
+ filterColumn +
198
+ "]"
199
+ );
200
+
201
+ filterInputElement.parent().removeClass("hidden");
202
+ filterInputElement.click();
167
203
  };
168
204
 
169
205
  // Search inside the dropdowns
170
- $(document).on('keyup', '[data-behaviour="dropdown-filter-search"]', function(e) {
171
- CmFilter.dropdown_search($(this))
172
- });
206
+ $(document).on(
207
+ "keyup",
208
+ '[data-behaviour="dropdown-filter-search"]',
209
+ function (e) {
210
+ CmFilter.dropdown_search($(this));
211
+ }
212
+ );
173
213
 
174
214
  // Method to decode the encoded nested and/or complex hash and convert it to
175
215
  // object that is used for filters while sending the data to the backend.
176
216
  var getParamsAsObject = function (query) {
177
- query = query.substring(query.indexOf('?') + 1);
217
+ query = query.substring(query.indexOf("?") + 1);
178
218
 
179
219
  var re = /([^&=]+)=?([^&]*)/g;
180
220
  var decodeRE = /\+/g;
@@ -183,199 +223,257 @@ var getParamsAsObject = function (query) {
183
223
  return decodeURIComponent(str.replace(decodeRE, " "));
184
224
  };
185
225
 
186
- var params = {}, e;
187
- while (e = re.exec(query)) {
188
- var k = decode(e[1]), v = decode(e[2]);
189
- if (k.substring(k.length - 2) === '[]') {
226
+ var params = {},
227
+ e;
228
+ while ((e = re.exec(query))) {
229
+ var k = decode(e[1]),
230
+ v = decode(e[2]);
231
+ if (k.substring(k.length - 2) === "[]") {
190
232
  k = k.substring(0, k.length - 2);
191
233
  (params[k] || (params[k] = [])).push(v);
192
- }
193
- else params[k] = v;
234
+ } else params[k] = v;
194
235
  }
195
236
 
196
237
  var assign = function (obj, keyPath, value) {
197
238
  var lastKeyIndex = keyPath.length - 1;
198
239
  for (var i = 0; i < lastKeyIndex; ++i) {
199
240
  var key = keyPath[i];
200
- if (!(key in obj))
201
- obj[key] = {}
241
+ if (!(key in obj)) obj[key] = {};
202
242
  obj = obj[key];
203
243
  }
204
244
  obj[keyPath[lastKeyIndex]] = value;
205
- }
245
+ };
206
246
 
207
247
  for (var prop in params) {
208
- var structure = prop.split('[');
248
+ var structure = prop.split("[");
209
249
  if (structure.length > 1) {
210
250
  var levels = [];
211
251
  structure.forEach(function (item, i) {
212
- var key = item.replace(/[?[\]\\ ]/g, '');
252
+ var key = item.replace(/[?[\]\\ ]/g, "");
213
253
  levels.push(key);
214
254
  });
215
255
  assign(params, levels, params[prop]);
216
- delete(params[prop]);
256
+ delete params[prop];
217
257
  }
218
258
  }
219
259
  return params;
220
260
  };
221
261
 
222
- $(document).on('click', '[data-behaviour="filter-input"]', function(e) {
223
- var filterType = $(this).data('filter-type')
224
- var filterColumn = $(this).data('db-column')
225
-
226
- var filterElement = $('[data-behaviour="filter"][data-filter-type=' + filterType + '][data-db-column=' + filterColumn +']')
227
-
228
- if (filterType == 'range') {
229
- filterElement.parent().toggleClass('hidden')
230
- } else if (filterType == 'date') {
231
- filterElement.click()
262
+ $(document).on("click", '[data-behaviour="filter-input"]', function (e) {
263
+ var filterType = $(this).data("filter-type");
264
+ var filterColumn = $(this).data("db-column");
265
+
266
+ var filterElement = $(
267
+ '[data-behaviour="filter"][data-filter-type=' +
268
+ filterType +
269
+ "][data-db-column=" +
270
+ filterColumn +
271
+ "]"
272
+ );
273
+
274
+ if (filterType == "range") {
275
+ filterElement.parent().toggleClass("hidden");
276
+ } else if (filterType == "date") {
277
+ filterElement.click();
232
278
  }
233
- })
279
+ });
234
280
 
235
281
  // Remove all the applied filters and reload the page
236
- $(document).on('click', '.clear-btn', function(e) {
237
- window.location.href = window.location.href.split("?")[0]
238
- })
282
+ $(document).on("click", ".clear-btn", function (e) {
283
+ window.location.href = window.location.href.split("?")[0];
284
+ });
239
285
 
240
- var unhideClearFilterBtn = function(filterValue) {
286
+ var unhideClearFilterBtn = function (filterValue) {
241
287
  if (isValueEmpty(filterValue)) {
242
- $('.clear-btn').removeClass('hidden')
288
+ $(".clear-btn").removeClass("hidden");
243
289
  }
244
- }
290
+ };
245
291
 
246
- $(document).on('click', '[data-behaviour="select-option"] [data-behaviour="multi-select-filter-checkbox"]', function(e) {
247
- $(this).prop('checked', !$(this).prop('checked'));
248
- })
292
+ $(document).on(
293
+ "click",
294
+ '[data-behaviour="select-option"] [data-behaviour="multi-select-filter-checkbox"]',
295
+ function (e) {
296
+ $(this).prop("checked", !$(this).prop("checked"));
297
+ }
298
+ );
249
299
  // Selecting options for single and multi select filters
250
- $(document).on('click', '[data-behaviour="select-option"]', function(e) {
251
- var filterType = $(this).data('filter-type')
252
- var filterColumn = $(this).data('db-column')
253
-
254
- if (filterType == 'single_select') {
255
- var filterValue = $(this).data('value')
256
- var filterText = $(this).text()
257
- if (!this.classList.contains('selected')) {
258
- if (this.parentNode.querySelector('.list-item.selected') != null) {
259
- this.parentNode.querySelector('.list-item.selected').classList.remove('selected');
300
+ $(document).on("click", '[data-behaviour="select-option"]', function (e) {
301
+ var filterType = $(this).data("filter-type");
302
+ var filterColumn = $(this).data("db-column");
303
+
304
+ if (filterType == "single_select") {
305
+ var filterValue = $(this).data("value");
306
+ var filterText = $(this).text();
307
+ if (!this.classList.contains("selected")) {
308
+ if (this.parentNode.querySelector(".list-item.selected") != null) {
309
+ this.parentNode
310
+ .querySelector(".list-item.selected")
311
+ .classList.remove("selected");
260
312
  }
261
- $(this).addClass('selected')
313
+ $(this).addClass("selected");
262
314
  }
263
315
 
264
- $(this).parents(':nth(4)').children(':first').children(':nth(1)').text(filterText)
265
- $(this).parents(':nth(4)').children(':first').children(':last').removeClass('hidden')
316
+ $(this)
317
+ .parents(":nth(4)")
318
+ .children(":first")
319
+ .children(":nth(1)")
320
+ .text(filterText);
321
+ $(this)
322
+ .parents(":nth(4)")
323
+ .children(":first")
324
+ .children(":last")
325
+ .removeClass("hidden");
266
326
 
267
327
  // Clear the search value post selection and regenerate the dropdown elements.
268
- var searchInputElement = $(this).parents(':nth(1)').children(':first').children()
269
- searchInputElement.val('')
270
- CmFilter.dropdown_search(searchInputElement)
271
-
272
- unhideClearFilterBtn(filterValue)
273
- getFilteredData(filterType, filterValue, filterColumn)
274
- }
275
- else if (filterType == 'multi_select') {
276
- var parentChip = $(this).parent().siblings(':first')
277
- var checkboxElement = $(this).find('[data-behaviour="multi-select-filter-checkbox"]')
278
- checkboxElement.prop('checked', !checkboxElement.prop('checked'))
279
- var checkedCount = $(this).parent().find('[data-behaviour="multi-select-filter-checkbox"]').filter(':checked').length
280
- var filterValue = []
281
- var filterValueText = []
282
- if (checkboxElement.prop('checked')) {
283
- var chip = $('<div class="chip"></div>')
284
- var firstSpan = $('<span></span>').text($(this).text())
285
- var secondSpan = $('<span data-behaviour="selected-chip"><i class="fa fa-times"></i></span>')
286
- parentChip.prepend(chip.append(firstSpan).append(secondSpan))
328
+ var searchInputElement = $(this)
329
+ .parents(":nth(1)")
330
+ .children(":first")
331
+ .children();
332
+ searchInputElement.val("");
333
+ CmFilter.dropdown_search(searchInputElement);
334
+
335
+ unhideClearFilterBtn(filterValue);
336
+ getFilteredData(filterType, filterValue, filterColumn);
337
+ } else if (filterType == "multi_select") {
338
+ var parentChip = $(this).parent().siblings(":first");
339
+ var checkboxElement = $(this).find(
340
+ '[data-behaviour="multi-select-filter-checkbox"]'
341
+ );
342
+ checkboxElement.prop("checked", !checkboxElement.prop("checked"));
343
+ var checkedCount = $(this)
344
+ .parent()
345
+ .find('[data-behaviour="multi-select-filter-checkbox"]')
346
+ .filter(":checked").length;
347
+ var filterValue = [];
348
+ var filterValueText = [];
349
+ if (checkboxElement.prop("checked")) {
350
+ var chip = $('<div class="chip"></div>');
351
+ var firstSpan = $("<span></span>").text($(this).text());
352
+ var secondSpan = $(
353
+ '<span data-behaviour="selected-chip"><i class="fa fa-times"></i></span>'
354
+ );
355
+ parentChip.prepend(chip.append(firstSpan).append(secondSpan));
287
356
  } else {
288
- var chipElement = parentChip.find('.chip')
289
- for(var i = 0; i < chipElement.length; i++) {
357
+ var chipElement = parentChip.find(".chip");
358
+ for (var i = 0; i < chipElement.length; i++) {
290
359
  if ($(chipElement[i]).text() == $(this).text()) {
291
- $(chipElement[i]).remove()
292
- break
360
+ $(chipElement[i]).remove();
361
+ break;
293
362
  }
294
363
  }
295
364
  }
296
- $(this).parent().find('[data-behaviour="multi-select-filter-checkbox"]').filter(':checked').each(function() {
297
- filterValue.push($(this).parent().data('value'))
298
- filterValueText.push($(this).parent().text())
299
- })
365
+ $(this)
366
+ .parent()
367
+ .find('[data-behaviour="multi-select-filter-checkbox"]')
368
+ .filter(":checked")
369
+ .each(function () {
370
+ filterValue.push($(this).parent().data("value"));
371
+ filterValueText.push($(this).parent().text());
372
+ });
300
373
 
301
374
  if (checkedCount > 0) {
302
- parentChip.addClass('active')
303
- $(this).parents(':nth(1)').children(':last').addClass('active')
375
+ parentChip.addClass("active");
376
+ $(this).parents(":nth(1)").children(":last").addClass("active");
304
377
  } else {
305
- parentChip.removeClass('active')
306
- $(this).parents(':nth(1)').children(':last').removeClass('active')
378
+ parentChip.removeClass("active");
379
+ $(this).parents(":nth(1)").children(":last").removeClass("active");
307
380
  }
308
381
  // Truncate filter value logic
309
- var truncatedFilterValue = filterValueText[0]
382
+ var truncatedFilterValue = filterValueText[0];
310
383
  if (filterValue.length > 1) {
311
- truncatedFilterValue += ' + ' + (filterValue.length - 1);
384
+ truncatedFilterValue += " + " + (filterValue.length - 1);
312
385
  }
313
386
  // Update the filter input element with the truncated value
314
- var filterInputElement = $(this).parents(':nth(4)').children(':first')
387
+ var filterInputElement = $(this).parents(":nth(4)").children(":first");
315
388
  if (filterValue.length > 0) {
316
- filterInputElement.children(':nth(1)').text(truncatedFilterValue)
317
- filterInputElement.children(':last').removeClass('hidden')
389
+ filterInputElement.children(":nth(1)").text(truncatedFilterValue);
390
+ filterInputElement.children(":last").removeClass("hidden");
318
391
  } else {
319
- filterInputElement.children(':nth(1)').text('')
320
- filterInputElement.children(':last').addClass('hidden')
392
+ filterInputElement.children(":nth(1)").text("");
393
+ filterInputElement.children(":last").addClass("hidden");
321
394
  }
322
395
  // Clear the search value post selection and regenerate the dropdown elements.
323
- var searchInputElement = $(this).parents(':nth(1)').children(':first').children(':last')
324
- searchInputElement.val('')
325
- CmFilter.dropdown_search(searchInputElement)
326
- unhideClearFilterBtn(filterValue)
327
- getFilteredData(filterType, filterValue, filterColumn)
396
+ var searchInputElement = $(this)
397
+ .parents(":nth(1)")
398
+ .children(":first")
399
+ .children(":last");
400
+ searchInputElement.val("");
401
+ CmFilter.dropdown_search(searchInputElement);
402
+ unhideClearFilterBtn(filterValue);
403
+ getFilteredData(filterType, filterValue, filterColumn);
328
404
  }
329
405
  });
330
406
 
331
-
332
407
  // Remove single applied filter.
333
- $(document).on('click', '.filter-chip-remove', function(e) {
334
- var url = window.location.pathname
335
- var filterType = $(this).parent().data('filter-type')
336
- var filterColumn = $(this).parent().data('db-column')
408
+ $(document).on("click", ".filter-chip-remove", function (e) {
409
+ var url = window.location.pathname;
410
+ var filterType = $(this).parent().data("filter-type");
411
+ var filterColumn = $(this).parent().data("db-column");
337
412
 
338
- var searchParams = window.location.search
413
+ var searchParams = window.location.search;
339
414
  if (searchParams.length > 0) {
340
- var queryString = getParamsAsObject(searchParams)
341
- if (queryString['filters'][filterType] != undefined) {
342
- delete(queryString['filters'][filterType][filterColumn])
343
- var queryParam = jQuery.param(queryString)
344
- window.history.pushState("", "", url + '?' + queryParam);
345
- window.location.reload()
415
+ var queryString = getParamsAsObject(searchParams);
416
+ if (queryString["filters"][filterType] != undefined) {
417
+ delete queryString["filters"][filterType][filterColumn];
418
+ var queryParam = jQuery.param(queryString);
419
+ window.history.pushState("", "", url + "?" + queryParam);
420
+ window.location.reload();
346
421
  }
347
422
  }
348
423
  });
349
424
 
350
- $(document).on('click', '[data-behaviour="selected-chip"]', function(e) {
351
- var filterType = $(this).parents(':nth(5)').find('.filter-chip').data('filter-type');
352
- var filterColumn = $(this).parents(':nth(5)').find('.filter-chip').data('db-column');
353
- var filterValue = [];
425
+ $(document).on("click", '[data-behaviour="selected-chip"]', function (e) {
426
+ var filterType = $(this)
427
+ .parents(":nth(5)")
428
+ .find(".filter-chip")
429
+ .data("filter-type");
430
+ var filterColumn = $(this)
431
+ .parents(":nth(5)")
432
+ .find(".filter-chip")
433
+ .data("db-column");
434
+ var filterValue = [];
354
435
  var filterValueText = $(this).siblings().text();
355
- var selectElement = $('[data-behaviour="select-option"][data-filter-type=' + filterType + '][data-db-column=' + filterColumn + ']');
436
+ var selectElement = $(
437
+ '[data-behaviour="select-option"][data-filter-type=' +
438
+ filterType +
439
+ "][data-db-column=" +
440
+ filterColumn +
441
+ "]"
442
+ );
356
443
  $(this).parent().remove();
357
444
  for (var i = 0; i < selectElement.length; i++) {
358
- if ($(selectElement[i]).text() == filterValueText) {
359
- var checkboxElement = $(selectElement[i]).find('[data-behaviour="multi-select-filter-checkbox"]');
360
- checkboxElement.prop('checked', false); // Uncheck the box
361
- break;
362
- }
445
+ if ($(selectElement[i]).text() == filterValueText) {
446
+ var checkboxElement = $(selectElement[i]).find(
447
+ '[data-behaviour="multi-select-filter-checkbox"]'
448
+ );
449
+ checkboxElement.prop("checked", false); // Uncheck the box
450
+ break;
451
+ }
363
452
  }
364
- selectElement.find('[data-behaviour="multi-select-filter-checkbox"]').filter(':checked').each(function() {
365
- filterValue.push($(this).parent().data('value'));
366
- });
367
- var checkedCount = selectElement.find('[data-behaviour="multi-select-filter-checkbox"]').filter(':checked').length;
453
+ selectElement
454
+ .find('[data-behaviour="multi-select-filter-checkbox"]')
455
+ .filter(":checked")
456
+ .each(function () {
457
+ filterValue.push($(this).parent().data("value"));
458
+ });
459
+ var checkedCount = selectElement
460
+ .find('[data-behaviour="multi-select-filter-checkbox"]')
461
+ .filter(":checked").length;
368
462
  if (checkedCount < 1) {
369
- selectElement.parent().siblings(':first').removeClass('active');
370
- selectElement.parent().siblings(':last').removeClass('active');
463
+ selectElement.parent().siblings(":first").removeClass("active");
464
+ selectElement.parent().siblings(":last").removeClass("active");
371
465
  }
372
466
  unhideClearFilterBtn(filterValue);
373
467
  getFilteredData(filterType, filterValue, filterColumn);
374
468
  });
375
469
 
376
- $(document).on("change", '[data-behaviour="sort-column"], [data-behaviour="sort-direction"]', function (e) {
377
- getFilteredData(null, null, null, true);
378
- });
470
+ $(document).on(
471
+ "change",
472
+ '[data-behaviour="sort-column"], [data-behaviour="sort-direction"]',
473
+ function (e) {
474
+ getFilteredData(null, null, null, true);
475
+ }
476
+ );
379
477
 
380
478
  $(document).on("click", '[data-behaviour="reset-sort"]', function (e) {
381
479
  let url = window.location.pathname;
@@ -384,15 +482,15 @@ $(document).on("click", '[data-behaviour="reset-sort"]', function (e) {
384
482
  delete queryString["sort_direction"];
385
483
  let queryParam = jQuery.param(queryString);
386
484
  $.ajax({
387
- type: 'POST',
485
+ type: "POST",
388
486
  url: url + "/reset_sort_columns",
389
- success: function(data) {
487
+ success: function (data) {
390
488
  window.history.pushState("", "", url + "?" + queryParam);
391
489
  window.location.reload();
392
490
  },
393
- error: function(jqxhr, textStatus, errorThrown) {
491
+ error: function (jqxhr, textStatus, errorThrown) {
394
492
  console.log(errorThrown, textStatus);
395
- }
493
+ },
396
494
  });
397
495
  });
398
496
 
@@ -401,8 +499,13 @@ $(document).on(
401
499
  '[data-behaviour="multi-select-filter-apply"]',
402
500
  function (e) {
403
501
  $(this).parent();
404
- $(this).closest('[data-behaviour="multi-select-filter-dropdown"]').removeClass('show');
405
- $(this).closest('[data-behaviour="multi-select-filter-wrapper"]').find('[data-behaviour="filter-input"]').removeClass('show');
502
+ $(this)
503
+ .closest('[data-behaviour="multi-select-filter-dropdown"]')
504
+ .removeClass("show");
505
+ $(this)
506
+ .closest('[data-behaviour="multi-select-filter-wrapper"]')
507
+ .find('[data-behaviour="filter-input"]')
508
+ .removeClass("show");
406
509
  }
407
510
  );
408
511
 
@@ -410,56 +513,62 @@ $(document).on(
410
513
  "click",
411
514
  '[data-behaviour="multi-select-filter-clear"]',
412
515
  function (e) {
413
- const dropdown = $(this).closest('[data-behaviour="multi-select-filter-dropdown"]');
516
+ const dropdown = $(this).closest(
517
+ '[data-behaviour="multi-select-filter-dropdown"]'
518
+ );
414
519
 
415
- const filterInputElement = $(this).parents(':nth(4)').children(':first')
416
- filterInputElement.children(':nth(1)').text('')
520
+ const filterInputElement = $(this).parents(":nth(4)").children(":first");
521
+ filterInputElement.children(":nth(1)").text("");
417
522
 
418
- const checkboxes = dropdown.find('[data-behaviour="multi-select-filter-checkbox"]:checked');
419
- checkboxes.each(function() {
523
+ const checkboxes = dropdown.find(
524
+ '[data-behaviour="multi-select-filter-checkbox"]:checked'
525
+ );
526
+ checkboxes.each(function () {
420
527
  this.checked = false;
421
528
  });
422
529
 
423
- const chips = dropdown.find('.chip');
424
- chips.each(function() {
530
+ const chips = dropdown.find(".chip");
531
+ chips.each(function () {
425
532
  $(this).remove();
426
533
  });
427
534
 
428
- const chipsArea = dropdown.find('[data-behaviour="multi-select-filter-chips-area"]');
429
- chipsArea.removeClass('active');
535
+ const chipsArea = dropdown.find(
536
+ '[data-behaviour="multi-select-filter-chips-area"]'
537
+ );
538
+ chipsArea.removeClass("active");
430
539
 
431
540
  const filter_element = dropdown.prev();
432
- const db_column = filter_element.attr('data-db-column');
433
- getFilteredData(filter_element.attr('data-filter-type'), [], db_column);
541
+ const db_column = filter_element.attr("data-db-column");
542
+ getFilteredData(filter_element.attr("data-filter-type"), [], db_column);
434
543
  }
435
544
  );
436
545
 
437
- const initializeFilterLabels = function(filterParams) {
438
- Object.keys(filterParams).forEach(filterType => {
439
- const filterObj = filterParams[filterType];
440
- Object.keys(filterObj).forEach(filterColumn => {
441
- const filterChip = $(`[data-db-column="${filterColumn}"]`);
442
- const filterName = filterChip.find('.filter-name');
443
-
444
- // Append "is" to indicate active filter
445
- if (filterName.length && !filterName.text().endsWith('is')) {
446
- filterName.html(`${filterName.text()} is `);
447
- filterName.data('appended', true);
448
- }
449
- });
546
+ const initializeFilterLabels = function (filterParams) {
547
+ Object.keys(filterParams).forEach((filterType) => {
548
+ const filterObj = filterParams[filterType];
549
+ Object.keys(filterObj).forEach((filterColumn) => {
550
+ const filterChip = $(`[data-db-column="${filterColumn}"]`);
551
+ const filterName = filterChip.find(".filter-name");
552
+
553
+ // Append "is" to indicate active filter
554
+ if (filterName.length && !filterName.text().endsWith("is")) {
555
+ filterName.html(`${filterName.text()} is `);
556
+ filterName.data("appended", true);
557
+ }
558
+ });
450
559
  });
451
560
  };
452
561
 
453
- $(document).ready(function() {
562
+ $(document).ready(function () {
454
563
  const initialFilterParams = getParamsAsObject(window.location.search);
455
564
  initializeFilterLabels(initialFilterParams.filters || {});
456
565
  });
457
566
 
458
- $(document).ready(function() {
459
- const chipsAreas = document.querySelectorAll('[data-behaviour="multi-select-filter-chips-area"]');
460
- chipsAreas.forEach(function(chipsArea) {
461
- chipsArea.classList.add('active');
567
+ $(document).ready(function () {
568
+ const chipsAreas = document.querySelectorAll(
569
+ '[data-behaviour="multi-select-filter-chips-area"]'
570
+ );
571
+ chipsAreas.forEach(function (chipsArea) {
572
+ chipsArea.classList.add("active");
462
573
  });
463
574
  });
464
-
465
-
@@ -1,5 +1,6 @@
1
1
  // This file is shared between rails 6 and 7 version
2
2
  import LocalTime from "./local-time";
3
+
3
4
  $(document).on(
4
5
  "keypress keyup blur",
5
6
  "[data-behaviour='decimal-only'], [data-behaviour='filter'][data-filter-type='range']",
@@ -55,6 +56,11 @@ $(document).on("click", '[data-behaviour="offcanvas"]', function (e) {
55
56
  );
56
57
  drawerForm.show();
57
58
  initializeComponents();
59
+ $("#cm-drawer .select-2").select2({
60
+ theme: "bootstrap-5",
61
+ dropdownParent: "#cm-drawer",
62
+ });
63
+
58
64
  handleDrawerFormSubmission(drawerForm);
59
65
  },
60
66
  error: function (error) {
@@ -246,4 +252,4 @@ export function initializeComponents() {
246
252
  var calculatedHeight = "calc(100vh - " + headerElemHeight + "px" + ")";
247
253
  $(".table-wrapper").css("maxHeight", calculatedHeight);
248
254
  LocalTime.start();
249
- }
255
+ }
@@ -77,8 +77,7 @@
77
77
  &:focus {
78
78
  border-color: $brand-color !important;
79
79
  outline: 0 !important;
80
- box-shadow:
81
- inset 0 1px 1px rgba(0, 0, 0, 0.075),
80
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
82
81
  0 0 8px rgba(102, 175, 233, 0.6) !important;
83
82
  }
84
83
  }
@@ -96,8 +95,7 @@
96
95
  &:focus {
97
96
  border-color: $brand-color;
98
97
  outline: 0;
99
- box-shadow:
100
- inset 0 1px 1px rgba(0, 0, 0, 0.075),
98
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
101
99
  0 0 8px rgba(102, 175, 233, 0.6);
102
100
  }
103
101
  .select2-selection__rendered {
@@ -132,3 +132,7 @@ a {
132
132
 
133
133
  z-index: 11;
134
134
  }
135
+
136
+ .toast {
137
+ background-color: $white;
138
+ }
@@ -2,11 +2,14 @@ module CmAdmin
2
2
  class StaticController < ::ActionController::Base
3
3
  layout 'static'
4
4
 
5
- def dashboard
6
- end
5
+ def dashboard; end
7
6
 
8
- def error_403
9
-
7
+ def index
8
+ fallback_path = current_user.present? ? "#{CmAdmin::Engine.mount_path}/users" : '/users/sign_in'
9
+ redirect_path = current_user&.cm_role&.default_redirect_path || fallback_path
10
+ redirect_to redirect_path
10
11
  end
12
+
13
+ def error_403; end
11
14
  end
12
15
  end
@@ -4,6 +4,19 @@ class CmRole < ApplicationRecord
4
4
  has_many :cm_permissions
5
5
 
6
6
  validates :name, uniqueness: true, presence: true
7
+ validate :valid_default_redirect_path
7
8
 
8
9
  has_paper_trail
10
+
11
+ private
12
+
13
+ def valid_default_redirect_path
14
+ return if default_redirect_path.blank?
15
+
16
+ begin
17
+ Rails.application.routes.recognize_path(default_redirect_path)
18
+ rescue ActionController::RoutingError
19
+ errors.add(:default_redirect_path, 'should be valid rails path')
20
+ end
21
+ end
9
22
  end
@@ -18,7 +18,6 @@ module CmAdmin::CmRole
18
18
  cm_show page_title: :name do
19
19
  custom_action name: 'create_role_permission', route_type: 'member', verb: 'post', path: ':id/create_role_permission',
20
20
  display_type: :route do
21
- # allowed_params = params.permit(role_permission: []).to_h
22
21
  @role = CmRole.find(params[:id])
23
22
  params[:role_permission].except(:submit).each do |model_name, action_arr|
24
23
  action_names = action_arr.select { |k, v| k if v.key?('is_checked') }.keys
@@ -37,6 +36,7 @@ module CmAdmin::CmRole
37
36
  tab :profile, '' do
38
37
  cm_show_section 'Role details' do
39
38
  field :name
39
+ field :default_redirect_path
40
40
  field :created_at, field_type: :date, format: '%d %b, %Y'
41
41
  field :updated_at, field_type: :date, format: '%d %b, %Y'
42
42
  end
@@ -47,12 +47,14 @@ module CmAdmin::CmRole
47
47
  cm_new page_title: 'Add Role', page_description: 'Enter all details to add role' do
48
48
  cm_section 'Details' do
49
49
  form_field :name, input_type: :string
50
+ form_field :default_redirect_path, input_type: :string, helper_text: 'Enter a correct path to have default redirect path for this role. Usually it will be /cm_admin/<model name in plural>. Example: /cm_admin/users'
50
51
  end
51
52
  end
52
53
 
53
54
  cm_edit page_title: 'Edit Role', page_description: 'Enter all details to edit role' do
54
55
  cm_section 'Details' do
55
56
  form_field :name, input_type: :string
57
+ form_field :default_redirect_path, input_type: :string, helper_text: 'Enter a correct path to have default redirect path for this role. Usually it will be /cm_admin/<model name in plural>. Example: /cm_admin/users'
56
58
  end
57
59
  end
58
60
  end
@@ -55,4 +55,5 @@
55
55
  p.count-text.m-0 Showing #{@ar_object.pagy.from} to #{@ar_object.pagy.to} out of #{@ar_object.pagy.count}
56
56
  == render partial: 'cm_admin/main/cm_pagy_nav', locals: { pagy: @ar_object.pagy }
57
57
 
58
- / = render partial: 'cm_admin/main/member_custom_action_modal', locals: { cm_model: @model, ar_collection: @ar_object }
58
+ = column_pop_up(@model)
59
+ = manage_column_pop_up(@model)
@@ -11,4 +11,7 @@
11
11
 
12
12
  .pagination-bar.kanban-pagination
13
13
  .btn.btn-primary.kanban-show-more data-page=1 Show more
14
- = render partial: 'cm_admin/main/show_as_drawer'
14
+ = render partial: 'cm_admin/main/show_as_drawer'
15
+
16
+ = column_pop_up(@model)
17
+ = manage_column_pop_up(@model)
@@ -52,3 +52,6 @@
52
52
  .pagination-bar
53
53
  p.count-text.m-0 Showing #{@ar_object.pagy.from} to #{@ar_object.pagy.to} out of #{@ar_object.pagy.count}
54
54
  == render partial: 'cm_admin/main/cm_pagy_nav', locals: { pagy: @ar_object.pagy }
55
+
56
+ = column_pop_up(@model)
57
+ = manage_column_pop_up(@model)
@@ -15,6 +15,3 @@
15
15
  == render "cm_admin/#{@model.name.underscore}/card"
16
16
  - elsif params[:view_type] == 'kanban' || @current_action.view_type == :kanban
17
17
  == render 'cm_admin/main/kanban'
18
- = column_pop_up(@model)
19
- = manage_column_pop_up(@model)
20
-
@@ -48,25 +48,25 @@ module Authentication
48
48
  before_action :check_current_user
49
49
  before_action :set_params
50
50
  end
51
-
51
+
52
52
  def set_params
53
53
  Current.request_params = params if params
54
54
  end
55
55
 
56
- # Add other methods here
56
+ # Add other methods here
57
57
 
58
58
  end
59
59
  ```
60
60
 
61
- 3. Add `belongs_to :cm_role, optional: true` in the `User` model.
62
- 4. Include `CmRole` in the `config.included_models` section of `config/initializers/zcm_admin.rb`.
61
+ 3. Add `belongs_to :cm_role, optional: true` in the `User` model.
62
+ 4. Include `CmRole` in the `config.included_models` section of `config/initializers/zcm_admin.rb`.
63
63
  5. Assign `cm_role_id` to `1` for any user in the `User` Model, and use that user to log in.
64
64
 
65
65
  ## Setting up scopes
66
66
 
67
67
  By default, `Full Access` scopes is added to each permission item. To add additional scopes, use the following syntax:
68
68
 
69
- ```ruby
69
+ ````ruby
70
70
  ...
71
71
  cm_admin do
72
72
  actions only: []
@@ -91,7 +91,7 @@ cm_admin do
91
91
  page_title 'User'
92
92
  end
93
93
  end
94
- ```
94
+ ````
95
95
 
96
96
  Then, create a policy file for the respective model, e.g., `app/policies/cm_admin/user_policy.rb`:
97
97
 
@@ -106,7 +106,6 @@ end
106
106
 
107
107
  This structure helps ensure that your application's role and permission management is both flexible and secure.
108
108
 
109
-
110
109
  ## Permission based fields
111
110
 
112
111
  We can apply permission logic to display a field on the interface. You can do this with the following syntax.
@@ -126,3 +125,19 @@ end
126
125
 
127
126
  ```
128
127
 
128
+ ## Adding Default Redirect Path for a Role
129
+
130
+ - We can add default redirect path for a role via cm admin.
131
+ - need to add this on `routes.rb`.
132
+
133
+ ```ruby
134
+ ...
135
+ root 'cm_admin/static#index'
136
+ ```
137
+
138
+ - Create a migration to add a column for default redirect path. (Will be automatically added in new apps)
139
+
140
+ ```ruby
141
+ ...
142
+ add_column :cm_roles, :default_redirect_path, :string, default: "#{CmAdmin::Engine.mount_path}/users"
143
+ ```
@@ -1,3 +1,3 @@
1
1
  module CmAdmin
2
- VERSION = '3.0.14'
2
+ VERSION = '3.0.15'
3
3
  end
@@ -84,7 +84,7 @@ module CmAdmin
84
84
  end
85
85
 
86
86
  def toast_message(message, toast_type)
87
- tag.div class: 'position-fixed bottom-0 end-0 p-3', style: 'z-index: 11' do
87
+ tag.div class: 'cm-toast-container' do
88
88
  tag.div class: "toast #{toast_type == 'alert' ? 'text-white bg-danger' : ''}", role: 'alert', 'aria-live': 'assertive', 'aria-atomic': 'true', data: { behaviour: 'toast' } do
89
89
  tag.div class: 'd-flex' do
90
90
  concat tag.div message.html_safe, class: 'toast-body'
@@ -6,7 +6,7 @@ module CmAdmin
6
6
  source_root File.expand_path('templates', __dir__)
7
7
 
8
8
  def create_migration
9
- generate 'migration', 'CreateCmRole name:string'
9
+ generate 'migration', 'CreateCmRole name:string default_redirect_path:string'
10
10
  generate 'migration', 'CreateCmPermission action_name:string action_display_name:string ar_model_name:string scope_name:string cm_role:references'
11
11
  rake 'db:migrate'
12
12
  puts "Created migration"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cm-admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.14
4
+ version: 3.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: exe
16
16
  cert_chain: []
17
- date: 2024-11-08 00:00:00.000000000 Z
17
+ date: 2024-11-18 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: caxlsx_rails