bastion 4.3.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d51f22893a276196b2ddf87221c5f4d3690a9b13
4
- data.tar.gz: 6fc3afe5f918a577dab6860644f87cc6364ebfde
3
+ metadata.gz: 53eb3be4777021eaac12603429045c2b6a75dfcc
4
+ data.tar.gz: 00a4c50f7065293da92e5f921713c2e0b1579964
5
5
  SHA512:
6
- metadata.gz: fa1bf691ed2d238091e8f59f83d044bbbf5d5e288dbdfcf221181f4f3ea25e99249dd9262210ef64b4b6b7de1c646e6bfb9f682a22af2a75b9afd4c63df7330d
7
- data.tar.gz: ed1f7879352f95741e8ca93ee8cf0799b93adf20fa1a3fc25d0a09b0e777d4a18a7965abca3734606dd79e20b172a8224eb4e4125b17fc27c033a5773bdeab61
6
+ metadata.gz: aec99b88057a13f935fa09711fe332585a229937685cff963f384c327323b5b4c991883ce8764b8ae1391addbbf037095ff119465f2a0b633d5b145397d064c0
7
+ data.tar.gz: ad1e8891be0ba0a795ce733630ade101b0a326c595d40e1b70802b528a9247ef5dcf836070ffb60cb7ca409f8b36bf137e17e08b5c26ca6c7162da62d7736f16
@@ -6,7 +6,6 @@ BASTION_MODULES = [
6
6
  'angular-blocks',
7
7
  'ngAnimate',
8
8
  'ngSanitize',
9
- 'infinite-scroll',
10
9
  'templates',
11
10
  'ui.bootstrap',
12
11
  'ui.bootstrap.tpls',
@@ -5,7 +5,6 @@
5
5
  //= require "bastion/angular-ui-router/angular-ui-router"
6
6
  //= require "bastion/angular-uuid4/angular-uuid4.js"
7
7
  //= require "bastion/ngUpload/ng-upload"
8
- //= require "bastion/ngInfiniteScroll/ng-infinite-scroll.js"
9
8
  //= require "bastion/angular-gettext/angular-gettext"
10
9
  //= require "bastion/angular-blocks/angular-blocks"
11
10
  //= require "bastion/angular-breadcrumb/angular-breadcrumb"
@@ -15,6 +15,7 @@
15
15
  element.bind('keydown keypress', function (event) {
16
16
  if (event.which === 13) {
17
17
  scope.$apply(attrs.bstOnEnter);
18
+ event.preventDefault();
18
19
  }
19
20
  });
20
21
  }
@@ -4,8 +4,7 @@
4
4
  *
5
5
  * @requires $location
6
6
  * @requires $q
7
- * @requires $timeout
8
- * @requires $rootScope
7
+ * @requires entriesPerPage
9
8
  * @requires TableCache
10
9
  * @requires GlobalNotification
11
10
  *
@@ -31,10 +30,9 @@
31
30
  </pre>
32
31
  */
33
32
  angular.module('Bastion.components').factory('Nutupane',
34
- ['$location', '$q', '$timeout', '$rootScope', 'TableCache', 'GlobalNotification', function ($location, $q, $timeout, $rootScope, TableCache, GlobalNotification) {
33
+ ['$location', '$q', 'entriesPerPage', 'TableCache', 'GlobalNotification', function ($location, $q, entriesPerPage, TableCache, GlobalNotification) {
35
34
  var Nutupane = function (resource, params, action) {
36
- var self = this,
37
- orgSwitcherRegex = new RegExp("/(organizations|locations)/(.+/)*(select|clear)");
35
+ var self = this;
38
36
 
39
37
  // TODO: remove me
40
38
  // http://projects.theforeman.org/issues/18079
@@ -44,7 +42,29 @@ angular.module('Bastion.components').factory('Nutupane',
44
42
  return $location.path().split('/').join('-').slice(1);
45
43
  }
46
44
 
45
+ function setQueryStrings() {
46
+ if (params.paged) {
47
+ $location.search("page", params.page).replace();
48
+ $location.search("per_page", params['per_page']).replace();
49
+ }
50
+
51
+ if (params.search) {
52
+ $location.search(self.searchKey, params.search).replace();
53
+ }
54
+
55
+ if (params.sort_by) {
56
+ $location.search("sortBy", params['sort_by']).replace();
57
+ }
58
+
59
+ if (params['sort_order']) {
60
+ $location.search("sortOrder", params['sort_order']).replace();
61
+ }
62
+ }
63
+
47
64
  params = params || {};
65
+ params.paged = true;
66
+ params.page = $location.search().page || 1;
67
+ params['per_page'] = $location.search().perPage || entriesPerPage;
48
68
 
49
69
  self.searchKey = action ? action + 'Search' : 'search';
50
70
 
@@ -57,17 +77,10 @@ angular.module('Bastion.components').factory('Nutupane',
57
77
  initialLoad: true
58
78
  };
59
79
 
60
- // Set default resource values
61
- resource.page = 0;
62
- resource.subtotal = "0";
63
- resource.total = "0";
64
- resource.results = [];
65
-
66
- self.load = function (replace) {
80
+ self.load = function () {
67
81
  var deferred = $q.defer(),
68
82
  table = self.table;
69
83
 
70
- replace = replace || false;
71
84
  table.working = true;
72
85
 
73
86
  if (table.initialLoad) {
@@ -76,7 +89,6 @@ angular.module('Bastion.components').factory('Nutupane',
76
89
  table.searchCompleted = false;
77
90
  }
78
91
 
79
- params.page = table.resource.page + 1;
80
92
  params.search = table.searchTerm || "";
81
93
  params.search = self.searchTransform(params.search);
82
94
 
@@ -90,11 +102,7 @@ angular.module('Bastion.components').factory('Nutupane',
90
102
  row.selected = table.allResultsSelected;
91
103
  });
92
104
 
93
- if (replace) {
94
- table.rows = response.results;
95
- } else {
96
- table.rows = table.rows.concat(response.results);
97
- }
105
+ table.rows = response.results;
98
106
  table.resource.page = parseInt(response.page, 10);
99
107
 
100
108
  if (table.initialSelectAll) {
@@ -102,21 +110,23 @@ angular.module('Bastion.components').factory('Nutupane',
102
110
  table.initialSelectAll = false;
103
111
  }
104
112
 
105
- // This $timeout is necessary to cause a digest cycle
106
- // in order to prevent loading two sets of results.
107
- $timeout(function () {
108
- deferred.resolve(response);
109
- table.resource = response;
110
- table.resource.page = parseInt(response.page, 10);
113
+ deferred.resolve(response);
114
+ table.resource = response;
115
+ table.resource.page = parseInt(response.page, 10);
111
116
 
112
- if (self.selectAllMode) {
113
- table.selectAll(true);
114
- }
115
- table.resource.offset = table.rows.length;
117
+ if (self.selectAllMode) {
118
+ table.selectAll(true);
119
+ }
120
+
121
+ if (table.resource.page > 1) {
122
+ table.resource.offset = (table.resource.page - 1) * table.resource['per_page'] + 1;
123
+ } else {
124
+ table.resource.offset = 1;
125
+ }
126
+
127
+ TableCache.setTable(getTableName(), table);
128
+ setQueryStrings();
116
129
 
117
- TableCache.setTable(getTableName(), table);
118
- $rootScope.$emit('nutupane:loaded');
119
- }, 0);
120
130
  table.working = false;
121
131
  table.refreshing = false;
122
132
  });
@@ -271,8 +281,8 @@ angular.module('Bastion.components').factory('Nutupane',
271
281
  $location.search(self.searchKey, searchTerm);
272
282
  self.table.searchTerm = searchTerm;
273
283
  self.table.resource.page = 1;
284
+ self.table.params.page = 1;
274
285
  self.table.rows = [];
275
- self.table.closeItem();
276
286
  self.table.selectAllResults(false);
277
287
 
278
288
  if (!self.table.working) {
@@ -291,13 +301,6 @@ angular.module('Bastion.components').factory('Nutupane',
291
301
  self.table.searchCompleted = true;
292
302
  };
293
303
 
294
- // Must be overridden
295
- self.table.closeItem = function () {
296
- if (!self.masterOnly) {
297
- throw "Nutupane closeItem not implemented. If you are using Nutupane functionality with master-detail please pass 'masterOnly' to your Nutupane declaration";
298
- }
299
- };
300
-
301
304
  self.table.replaceRow = function (row) {
302
305
  var index, selected;
303
306
  index = null;
@@ -320,27 +323,60 @@ angular.module('Bastion.components').factory('Nutupane',
320
323
  self.table.resource.total += 1;
321
324
  };
322
325
 
323
- self.table.nextPage = function () {
324
- var table = self.table;
325
- if (table.working || !table.hasMore()) {
326
- return false;
326
+ self.table.onFirstPage = function () {
327
+ return self.table.resource.page === 1;
328
+ };
329
+
330
+ self.table.onLastPage = function () {
331
+ return self.table.resource.page >= self.table.resource.subtotal / self.table.resource.per_page;
332
+ };
333
+
334
+ self.table.getPageEnd = function () {
335
+ var table = self.table, pageEnd;
336
+
337
+ pageEnd = table.resource.offset + table.rows.length - 1;
338
+
339
+ if (pageEnd > table.resource.subtotal) {
340
+ pageEnd = table.resource.subtotal;
327
341
  }
328
- return self.query();
342
+
343
+ return pageEnd;
329
344
  };
330
345
 
331
- self.table.hasMore = function () {
332
- var length = self.table.rows.length,
333
- subtotal = self.table.resource.subtotal,
334
- hasMore = false,
335
- justBegun;
346
+ self.table.firstPage = function () {
347
+ return self.table.changePage(1);
348
+ };
336
349
 
337
- if (!subtotal) {
338
- hasMore = false;
339
- } else {
340
- justBegun = (length === 0 && subtotal !== 0);
341
- hasMore = (length < subtotal) || justBegun;
350
+ self.table.previousPage = function () {
351
+ var previousPage = parseInt(params.page, 10) - 1;
352
+ return self.table.changePage(previousPage);
353
+ };
354
+
355
+ self.table.nextPage = function () {
356
+ var nextPage = parseInt(params.page, 10) + 1;
357
+ return self.table.changePage(nextPage);
358
+ };
359
+
360
+ self.table.lastPage = function () {
361
+ var table = self.table,
362
+ lastPage = Math.ceil(table.resource.subtotal / table.resource.per_page);
363
+ return table.changePage(lastPage);
364
+ };
365
+
366
+ self.table.changePage = function (pageNumber) {
367
+ if (pageNumber) {
368
+ params.page = pageNumber;
369
+ self.table.resource.page = pageNumber;
342
370
  }
343
- return hasMore;
371
+
372
+ return self.load();
373
+ };
374
+
375
+ self.table.pageSizes = _.uniq(_([25, 50, 75, 100, entriesPerPage]).sortBy().value());
376
+
377
+ self.table.updatePageSize = function () {
378
+ params.page = 1;
379
+ self.query();
344
380
  };
345
381
 
346
382
  // Wraps the table.selectAll() function if selectAllResultsEnabled is not set
@@ -394,12 +430,10 @@ angular.module('Bastion.components').factory('Nutupane',
394
430
  self.table.searchTerm = $location.search()[self.searchKey];
395
431
  };
396
432
 
397
- $rootScope.$on('$locationChangeStart', function (event, newUrl) {
398
- if (newUrl.match(orgSwitcherRegex)) {
399
- self.table.closeItem();
400
- }
401
- });
433
+ // Load initial set of results
434
+ self.load();
402
435
  };
436
+
403
437
  return Nutupane;
404
438
  }]
405
439
  );
@@ -1,11 +1,11 @@
1
1
  <div class="row toolbar-pf table-view-pf-toolbar-external" ng-class="{'empty-table': table.rows.length === 0}">
2
2
  <div class="col-sm-12">
3
3
  <form class="toolbar-pf-actions">
4
- <div class="form-group toolbar-pf-filter">
5
- <div class="form-group toolbar-pf-search-filter">
6
- <span data-block="search-filter"></span>
7
- </div>
4
+ <div class="form-group toolbar-pf-search-filter">
5
+ <span data-block="search-filter"></span>
6
+ </div>
8
7
 
8
+ <div class="form-group toolbar-pf-filter">
9
9
  <div data-block="search">
10
10
  <div class="input-group">
11
11
  <input type="text"
@@ -23,7 +23,7 @@
23
23
  <button class="btn btn-default"
24
24
  type="button"
25
25
  ng-click='table.search("") && (table.searchCompleted = false)'
26
- ng-show="table.searchCompleted && table.searchTerm">
26
+ ng-show="table.searchTerm">
27
27
  <i class="fa fa-times"></i>
28
28
  </button>
29
29
  <button ng-click="table.search(table.searchTerm)" class="btn btn-default" type="button">
@@ -48,25 +48,17 @@
48
48
  </form>
49
49
 
50
50
  <div class="row toolbar-pf-results" ng-show="table.rows.length > 0">
51
- <div class="col-sm-9">
52
- <span translate>Showing {{ table.rows.length }} of {{ table.resource.subtotal }} ({{ table.resource.total }} Total)</span>
53
- </div>
54
-
51
+ <div class="col-sm-9"></div>
55
52
  <div class="col-sm-3 table-view-pf-select-results" ng-show="table.rowSelect">
56
- <span translate>{{ table.numSelected }} Selected</span>
53
+ <span translate>{{ table.numSelected }} of {{ table.resource.total }} Selected</span>
57
54
  </div>
58
55
  </div>
59
56
  </div>
60
57
  </div>
61
58
 
62
- <div bst-table="table" nutupane-table>
59
+ <div bst-table="table">
63
60
  <div class="row">
64
61
  <div class="col-sm-12">
65
- <div class="loading-mask" ng-show="table.refreshing || table.working" >
66
- <i class="fa fa-spinner fa-spin"></i>
67
- <span>{{ "Loading..." | translate }}</span>
68
- </div>
69
-
70
62
  <p bst-alert="info" ng-show="table.rows.length === 0 && !table.working && !table.searchTerm && !table.searchCompleted">
71
63
  <span data-block="no-rows-message"></span>
72
64
  </p>
@@ -74,11 +66,61 @@
74
66
  <span data-block="no-search-results-message"></span>
75
67
  </p>
76
68
 
77
- <div ng-show="table.rows.length > 0 && !(table.refreshing || table.working)" bst-container-scroll data="table.rows">
78
- <div infinite-scroll="table.nextPage()" infinite-scroll-container="'.container-scroll-wrapper'"
79
- infinite-scroll-listen-for-event="nutupane:loaded">
80
- <div data-block="table"></div>
81
- </div>
69
+ <div ng-show="table.rows.length > 0" ng-class="{'table-mask': table.refreshing || table.working}">
70
+ <div data-block="table"></div>
71
+
72
+ <form class="content-view-pf-pagination table-view-pf-pagination clearfix">
73
+ <div class="form-group">
74
+ <div class="pagination-pf-pagesize">
75
+ <select class="form-control" ng-model="table.params.per_page" ng-change="table.updatePageSize()"
76
+ ng-options="value for value in table.pageSizes">
77
+ </select>
78
+ </div>
79
+ <span translate>per page</span>
80
+ </div>
81
+ <div class="form-group">
82
+ <span>
83
+ <span class="pagination-pf-items-current">{{ table.resource.offset }} - {{ table.getPageEnd() }}</span>
84
+ <span translate>of </span>
85
+ <span class="pagination-pf-items-total">{{ table.resource.subtotal }}</span>
86
+ </span>
87
+ <ul class="pagination pagination-pf-back">
88
+ <li ng-class="{ disabled: table.onFirstPage() }">
89
+ <a ng-click="table.onFirstPage() || table.firstPage()" title="{{ 'First Page' | translate }}">
90
+ <span class="i fa fa-angle-double-left"></span>
91
+ </a>
92
+ </li>
93
+ <li ng-class="{ disabled: table.onFirstPage() }">
94
+ <a ng-click="table.onFirstPage() || table.previousPage()" title="{{ 'Previous Page' | translate }}">
95
+ <span class="i fa fa-angle-left"></span>
96
+ </a>
97
+ </li>
98
+ </ul>
99
+
100
+ <label for="currentPage" class="sr-only" translate>
101
+ Current Page
102
+ </label>
103
+ <input id="currentPage" class="pagination-pf-page" type="text" ng-model="table.params.page" ng-blur="table.changePage()" bst-on-enter="table.changePage()"/>
104
+
105
+ <span translate>of
106
+ <span class="pagination-pf-pages">{{ (table.resource.subtotal / table.resource.per_page) | roundUp }}</span>
107
+ </span>
108
+
109
+ <ul class="pagination pagination-pf-forward">
110
+ <li ng-class="{ disabled: table.onLastPage() }">
111
+ <a ng-click="table.onLastPage() || table.nextPage()" title=" {{ 'Next Page' | translate }}">
112
+ <span class="i fa fa-angle-right"></span>
113
+ </a>
114
+ </li>
115
+
116
+ <li ng-class="{ disabled: table.onLastPage() }">
117
+ <a ng-click="table.onLastPage() || table.lastPage()" title="{{ 'Last Page' | translate }}">
118
+ <span class="i fa fa-angle-double-right"></span>
119
+ </a>
120
+ </li>
121
+ </ul>
122
+ </div>
123
+ </form>
82
124
  </div>
83
125
  </div>
84
126
  </div>
@@ -0,0 +1,20 @@
1
+ (function () {
2
+ /**
3
+ * @ngdoc filter
4
+ * @name Bastion.utils.filter:roundUp
5
+ *
6
+ * @description
7
+ * Converts an ng-model to a number.
8
+ *
9
+ * @example
10
+ * {{ 107.5 | roundUp }}
11
+ */
12
+
13
+ function roundUp() {
14
+ return function (value) {
15
+ return Math.ceil(value);
16
+ };
17
+ }
18
+
19
+ angular.module('Bastion.utils').filter('roundUp', roundUp);
20
+ })();
@@ -28,10 +28,6 @@
28
28
  overflow-y: auto;
29
29
  }
30
30
 
31
- .table-mask {
32
- opacity: 0.4;
33
- }
34
-
35
31
  th.row-select,
36
32
  td.row-select {
37
33
  width: 25px;
@@ -79,4 +79,9 @@ html .toolbar-pf.table-view-pf-toolbar-external .toolbar-pf-filter {
79
79
  .modal-body {
80
80
  overflow-x: hidden;
81
81
  overflow-y: scroll;
82
+ }
83
+
84
+ // Add some margin to the bottom of the table footer
85
+ .content-view-pf-pagination {
86
+ margin-bottom: 20px;
82
87
  }
@@ -59,3 +59,11 @@
59
59
  width: 150px;
60
60
  }
61
61
  }
62
+
63
+ .table-mask {
64
+ opacity: 0.4;
65
+ }
66
+
67
+ .pagination-pf-pagesize {
68
+ margin-right: 5px;
69
+ }
@@ -18,6 +18,7 @@
18
18
  angular.module('Bastion').value('CurrentOrganization', "<%= Organization.current.id if Organization.current %>");
19
19
  angular.module('Bastion').value('contentAccessMode', "<%= Organization.current.try(:content_access_mode) if Organization.current %>");
20
20
  angular.module('Bastion').value('markActiveMenu', mark_active_menu);
21
+ angular.module('Bastion').value('entriesPerPage', "<%= Setting[:entries_per_page] %>");
21
22
  angular.module('Bastion').constant('BastionConfig', angular.fromJson('<%= Bastion.config.to_json.html_safe %>'));
22
23
  angular.module('Bastion.auth').value('CurrentUser', {
23
24
  id: <%= User.current.id %>,
data/bower.json CHANGED
@@ -17,7 +17,6 @@
17
17
  "angular-ui-router": "=0.3.1",
18
18
  "angular-uuid4": "0.1.0",
19
19
  "json3": "~3.2.4",
20
- "ngInfiniteScroll": "1.2.1",
21
20
  "ngUpload": "0.5.18"
22
21
  },
23
22
  "devDependencies": {
@@ -79,9 +78,6 @@
79
78
  },
80
79
  "ngUpload": {
81
80
  "javascripts/bastion/ngUpload": "ng-upload.js"
82
- },
83
- "ngInfiniteScroll": {
84
- "javascripts/bastion/ngInfiniteScroll": "build/ng-infinite-scroll.js"
85
81
  }
86
82
  }
87
83
  }
data/grunt/karma.js CHANGED
@@ -29,7 +29,6 @@ module.exports = {
29
29
  basePath + 'vendor/assets/javascripts/bastion/angular-ui-router/angular-ui-router.js',
30
30
  basePath + 'vendor/assets/javascripts/bastion/angular-gettext/angular-gettext.js',
31
31
  basePath + 'vendor/assets/javascripts/bastion/ngUpload/ng-upload.js',
32
- basePath + 'vendor/assets/javascripts/bastion/ngInfiniteScroll/ng-infinite-scroll.js',
33
32
  basePath + 'vendor/assets/javascripts/bastion/angular-breadcrumb/angular-breadcrumb.js',
34
33
  basePath + '.tmp/bower_components/angular-mocks/angular-mocks.js',
35
34
  basePath + '.tmp/bower_components/lodash/lodash.js',
@@ -1,3 +1,3 @@
1
1
  module Bastion
2
- VERSION = "4.3.1"
2
+ VERSION = "5.0.0"
3
3
  end