##// END OF EJS Templates
user-groups: fixed in_ filters for large ammount of data.
marcink -
r3624:1068a814 default
parent child Browse files
Show More
@@ -1,259 +1,271 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 import formencode
23 import formencode
24 import formencode.htmlfill
24 import formencode.htmlfill
25
25
26 from pyramid.httpexceptions import HTTPFound
26 from pyramid.httpexceptions import HTTPFound
27 from pyramid.view import view_config
27 from pyramid.view import view_config
28 from pyramid.response import Response
28 from pyramid.response import Response
29 from pyramid.renderers import render
29 from pyramid.renderers import render
30
30
31 from rhodecode import events
31 from rhodecode import events
32 from rhodecode.apps._base import BaseAppView, DataGridAppView
32 from rhodecode.apps._base import BaseAppView, DataGridAppView
33 from rhodecode.lib.auth import (
33 from rhodecode.lib.auth import (
34 LoginRequired, NotAnonymous, CSRFRequired, HasPermissionAnyDecorator)
34 LoginRequired, NotAnonymous, CSRFRequired, HasPermissionAnyDecorator)
35 from rhodecode.lib import helpers as h, audit_logger
35 from rhodecode.lib import helpers as h, audit_logger
36 from rhodecode.lib.utils2 import safe_unicode
36 from rhodecode.lib.utils2 import safe_unicode
37
37
38 from rhodecode.model.forms import UserGroupForm
38 from rhodecode.model.forms import UserGroupForm
39 from rhodecode.model.permission import PermissionModel
39 from rhodecode.model.permission import PermissionModel
40 from rhodecode.model.scm import UserGroupList
40 from rhodecode.model.scm import UserGroupList
41 from rhodecode.model.db import (
41 from rhodecode.model.db import (
42 or_, count, User, UserGroup, UserGroupMember)
42 or_, count, User, UserGroup, UserGroupMember, in_filter_generator)
43 from rhodecode.model.meta import Session
43 from rhodecode.model.meta import Session
44 from rhodecode.model.user_group import UserGroupModel
44 from rhodecode.model.user_group import UserGroupModel
45 from rhodecode.model.db import true
45 from rhodecode.model.db import true
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
49
49
50 class AdminUserGroupsView(BaseAppView, DataGridAppView):
50 class AdminUserGroupsView(BaseAppView, DataGridAppView):
51
51
52 def load_default_context(self):
52 def load_default_context(self):
53 c = self._get_local_tmpl_context()
53 c = self._get_local_tmpl_context()
54
54
55 PermissionModel().set_global_permission_choices(
55 PermissionModel().set_global_permission_choices(
56 c, gettext_translator=self.request.translate)
56 c, gettext_translator=self.request.translate)
57
57
58 return c
58 return c
59
59
60 # permission check in data loading of
60 # permission check in data loading of
61 # `user_groups_list_data` via UserGroupList
61 # `user_groups_list_data` via UserGroupList
62 @LoginRequired()
62 @LoginRequired()
63 @NotAnonymous()
63 @NotAnonymous()
64 @view_config(
64 @view_config(
65 route_name='user_groups', request_method='GET',
65 route_name='user_groups', request_method='GET',
66 renderer='rhodecode:templates/admin/user_groups/user_groups.mako')
66 renderer='rhodecode:templates/admin/user_groups/user_groups.mako')
67 def user_groups_list(self):
67 def user_groups_list(self):
68 c = self.load_default_context()
68 c = self.load_default_context()
69 return self._get_template_context(c)
69 return self._get_template_context(c)
70
70
71 # permission check inside
71 # permission check inside
72 @LoginRequired()
72 @LoginRequired()
73 @NotAnonymous()
73 @NotAnonymous()
74 @view_config(
74 @view_config(
75 route_name='user_groups_data', request_method='GET',
75 route_name='user_groups_data', request_method='GET',
76 renderer='json_ext', xhr=True)
76 renderer='json_ext', xhr=True)
77 def user_groups_list_data(self):
77 def user_groups_list_data(self):
78 self.load_default_context()
78 self.load_default_context()
79 column_map = {
79 column_map = {
80 'active': 'users_group_active',
80 'active': 'users_group_active',
81 'description': 'user_group_description',
81 'description': 'user_group_description',
82 'members': 'members_total',
82 'members': 'members_total',
83 'owner': 'user_username',
83 'owner': 'user_username',
84 'sync': 'group_data'
84 'sync': 'group_data'
85 }
85 }
86 draw, start, limit = self._extract_chunk(self.request)
86 draw, start, limit = self._extract_chunk(self.request)
87 search_q, order_by, order_dir = self._extract_ordering(
87 search_q, order_by, order_dir = self._extract_ordering(
88 self.request, column_map=column_map)
88 self.request, column_map=column_map)
89
89
90 _render = self.request.get_partial_renderer(
90 _render = self.request.get_partial_renderer(
91 'rhodecode:templates/data_table/_dt_elements.mako')
91 'rhodecode:templates/data_table/_dt_elements.mako')
92
92
93 def user_group_name(user_group_name):
93 def user_group_name(user_group_name):
94 return _render("user_group_name", user_group_name)
94 return _render("user_group_name", user_group_name)
95
95
96 def user_group_actions(user_group_id, user_group_name):
96 def user_group_actions(user_group_id, user_group_name):
97 return _render("user_group_actions", user_group_id, user_group_name)
97 return _render("user_group_actions", user_group_id, user_group_name)
98
98
99 def user_profile(username):
99 def user_profile(username):
100 return _render('user_profile', username)
100 return _render('user_profile', username)
101
101
102 auth_user_group_list = UserGroupList(
102 auth_user_group_list = UserGroupList(
103 UserGroup.query().all(), perm_set=['usergroup.admin'])
103 UserGroup.query().all(), perm_set=['usergroup.admin'])
104
104
105 allowed_ids = [-1]
105 allowed_ids = [-1]
106 for user_group in auth_user_group_list:
106 for user_group in auth_user_group_list:
107 allowed_ids.append(user_group.users_group_id)
107 allowed_ids.append(user_group.users_group_id)
108
108
109 user_groups_data_total_count = UserGroup.query()\
109 user_groups_data_total_count = UserGroup.query()\
110 .filter(UserGroup.users_group_id.in_(allowed_ids))\
110 .filter(or_(
111 # generate multiple IN to fix limitation problems
112 *in_filter_generator(UserGroup.users_group_id, allowed_ids)
113 ))\
111 .count()
114 .count()
112
115
113 user_groups_data_total_inactive_count = UserGroup.query()\
116 user_groups_data_total_inactive_count = UserGroup.query()\
114 .filter(UserGroup.users_group_id.in_(allowed_ids))\
117 .filter(or_(
118 # generate multiple IN to fix limitation problems
119 *in_filter_generator(UserGroup.users_group_id, allowed_ids)
120 ))\
115 .filter(UserGroup.users_group_active != true()).count()
121 .filter(UserGroup.users_group_active != true()).count()
116
122
117 member_count = count(UserGroupMember.user_id)
123 member_count = count(UserGroupMember.user_id)
118 base_q = Session.query(
124 base_q = Session.query(
119 UserGroup.users_group_name,
125 UserGroup.users_group_name,
120 UserGroup.user_group_description,
126 UserGroup.user_group_description,
121 UserGroup.users_group_active,
127 UserGroup.users_group_active,
122 UserGroup.users_group_id,
128 UserGroup.users_group_id,
123 UserGroup.group_data,
129 UserGroup.group_data,
124 User,
130 User,
125 member_count.label('member_count')
131 member_count.label('member_count')
126 ) \
132 ) \
127 .filter(UserGroup.users_group_id.in_(allowed_ids)) \
133 .filter(or_(
128 .outerjoin(UserGroupMember) \
134 # generate multiple IN to fix limitation problems
129 .join(User, User.user_id == UserGroup.user_id) \
135 *in_filter_generator(UserGroup.users_group_id, allowed_ids)
130 .group_by(UserGroup, User)
136 )) \
137 .outerjoin(UserGroupMember) \
138 .join(User, User.user_id == UserGroup.user_id) \
139 .group_by(UserGroup, User)
131
140
132 base_q_inactive = base_q.filter(UserGroup.users_group_active != true())
141 base_q_inactive = base_q.filter(UserGroup.users_group_active != true())
133
142
134 if search_q:
143 if search_q:
135 like_expression = u'%{}%'.format(safe_unicode(search_q))
144 like_expression = u'%{}%'.format(safe_unicode(search_q))
136 base_q = base_q.filter(or_(
145 base_q = base_q.filter(or_(
137 UserGroup.users_group_name.ilike(like_expression),
146 UserGroup.users_group_name.ilike(like_expression),
138 ))
147 ))
139 base_q_inactive = base_q.filter(UserGroup.users_group_active != true())
148 base_q_inactive = base_q.filter(UserGroup.users_group_active != true())
140
149
141 user_groups_data_total_filtered_count = base_q.count()
150 user_groups_data_total_filtered_count = base_q.count()
142 user_groups_data_total_filtered_inactive_count = base_q_inactive.count()
151 user_groups_data_total_filtered_inactive_count = base_q_inactive.count()
143
152
153 sort_defined = False
144 if order_by == 'members_total':
154 if order_by == 'members_total':
145 sort_col = member_count
155 sort_col = member_count
156 sort_defined = True
146 elif order_by == 'user_username':
157 elif order_by == 'user_username':
147 sort_col = User.username
158 sort_col = User.username
148 else:
159 else:
149 sort_col = getattr(UserGroup, order_by, None)
160 sort_col = getattr(UserGroup, order_by, None)
150
161
151 if isinstance(sort_col, count) or sort_col:
162 if sort_defined or sort_col:
152 if order_dir == 'asc':
163 if order_dir == 'asc':
153 sort_col = sort_col.asc()
164 sort_col = sort_col.asc()
154 else:
165 else:
155 sort_col = sort_col.desc()
166 sort_col = sort_col.desc()
156
167
157 base_q = base_q.order_by(sort_col)
168 base_q = base_q.order_by(sort_col)
158 base_q = base_q.offset(start).limit(limit)
169 base_q = base_q.offset(start).limit(limit)
159
170
160 # authenticated access to user groups
171 # authenticated access to user groups
161 auth_user_group_list = base_q.all()
172 auth_user_group_list = base_q.all()
162
173
163 user_groups_data = []
174 user_groups_data = []
164 for user_gr in auth_user_group_list:
175 for user_gr in auth_user_group_list:
165 user_groups_data.append({
176 row = {
166 "users_group_name": user_group_name(user_gr.users_group_name),
177 "users_group_name": user_group_name(user_gr.users_group_name),
167 "name_raw": h.escape(user_gr.users_group_name),
178 "name_raw": h.escape(user_gr.users_group_name),
168 "description": h.escape(user_gr.user_group_description),
179 "description": h.escape(user_gr.user_group_description),
169 "members": user_gr.member_count,
180 "members": user_gr.member_count,
170 # NOTE(marcink): because of advanced query we
181 # NOTE(marcink): because of advanced query we
171 # need to load it like that
182 # need to load it like that
172 "sync": UserGroup._load_sync(
183 "sync": UserGroup._load_sync(
173 UserGroup._load_group_data(user_gr.group_data)),
184 UserGroup._load_group_data(user_gr.group_data)),
174 "active": h.bool2icon(user_gr.users_group_active),
185 "active": h.bool2icon(user_gr.users_group_active),
175 "owner": user_profile(user_gr.User.username),
186 "owner": user_profile(user_gr.User.username),
176 "action": user_group_actions(
187 "action": user_group_actions(
177 user_gr.users_group_id, user_gr.users_group_name)
188 user_gr.users_group_id, user_gr.users_group_name)
178 })
189 }
190 user_groups_data.append(row)
179
191
180 data = ({
192 data = ({
181 'draw': draw,
193 'draw': draw,
182 'data': user_groups_data,
194 'data': user_groups_data,
183 'recordsTotal': user_groups_data_total_count,
195 'recordsTotal': user_groups_data_total_count,
184 'recordsTotalInactive': user_groups_data_total_inactive_count,
196 'recordsTotalInactive': user_groups_data_total_inactive_count,
185 'recordsFiltered': user_groups_data_total_filtered_count,
197 'recordsFiltered': user_groups_data_total_filtered_count,
186 'recordsFilteredInactive': user_groups_data_total_filtered_inactive_count,
198 'recordsFilteredInactive': user_groups_data_total_filtered_inactive_count,
187 })
199 })
188
200
189 return data
201 return data
190
202
191 @LoginRequired()
203 @LoginRequired()
192 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
204 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
193 @view_config(
205 @view_config(
194 route_name='user_groups_new', request_method='GET',
206 route_name='user_groups_new', request_method='GET',
195 renderer='rhodecode:templates/admin/user_groups/user_group_add.mako')
207 renderer='rhodecode:templates/admin/user_groups/user_group_add.mako')
196 def user_groups_new(self):
208 def user_groups_new(self):
197 c = self.load_default_context()
209 c = self.load_default_context()
198 return self._get_template_context(c)
210 return self._get_template_context(c)
199
211
200 @LoginRequired()
212 @LoginRequired()
201 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
213 @HasPermissionAnyDecorator('hg.admin', 'hg.usergroup.create.true')
202 @CSRFRequired()
214 @CSRFRequired()
203 @view_config(
215 @view_config(
204 route_name='user_groups_create', request_method='POST',
216 route_name='user_groups_create', request_method='POST',
205 renderer='rhodecode:templates/admin/user_groups/user_group_add.mako')
217 renderer='rhodecode:templates/admin/user_groups/user_group_add.mako')
206 def user_groups_create(self):
218 def user_groups_create(self):
207 _ = self.request.translate
219 _ = self.request.translate
208 c = self.load_default_context()
220 c = self.load_default_context()
209 users_group_form = UserGroupForm(self.request.translate)()
221 users_group_form = UserGroupForm(self.request.translate)()
210
222
211 user_group_name = self.request.POST.get('users_group_name')
223 user_group_name = self.request.POST.get('users_group_name')
212 try:
224 try:
213 form_result = users_group_form.to_python(dict(self.request.POST))
225 form_result = users_group_form.to_python(dict(self.request.POST))
214 user_group = UserGroupModel().create(
226 user_group = UserGroupModel().create(
215 name=form_result['users_group_name'],
227 name=form_result['users_group_name'],
216 description=form_result['user_group_description'],
228 description=form_result['user_group_description'],
217 owner=self._rhodecode_user.user_id,
229 owner=self._rhodecode_user.user_id,
218 active=form_result['users_group_active'])
230 active=form_result['users_group_active'])
219 Session().flush()
231 Session().flush()
220 creation_data = user_group.get_api_data()
232 creation_data = user_group.get_api_data()
221 user_group_name = form_result['users_group_name']
233 user_group_name = form_result['users_group_name']
222
234
223 audit_logger.store_web(
235 audit_logger.store_web(
224 'user_group.create', action_data={'data': creation_data},
236 'user_group.create', action_data={'data': creation_data},
225 user=self._rhodecode_user)
237 user=self._rhodecode_user)
226
238
227 user_group_link = h.link_to(
239 user_group_link = h.link_to(
228 h.escape(user_group_name),
240 h.escape(user_group_name),
229 h.route_path(
241 h.route_path(
230 'edit_user_group', user_group_id=user_group.users_group_id))
242 'edit_user_group', user_group_id=user_group.users_group_id))
231 h.flash(h.literal(_('Created user group %(user_group_link)s')
243 h.flash(h.literal(_('Created user group %(user_group_link)s')
232 % {'user_group_link': user_group_link}),
244 % {'user_group_link': user_group_link}),
233 category='success')
245 category='success')
234 Session().commit()
246 Session().commit()
235 user_group_id = user_group.users_group_id
247 user_group_id = user_group.users_group_id
236 except formencode.Invalid as errors:
248 except formencode.Invalid as errors:
237
249
238 data = render(
250 data = render(
239 'rhodecode:templates/admin/user_groups/user_group_add.mako',
251 'rhodecode:templates/admin/user_groups/user_group_add.mako',
240 self._get_template_context(c), self.request)
252 self._get_template_context(c), self.request)
241 html = formencode.htmlfill.render(
253 html = formencode.htmlfill.render(
242 data,
254 data,
243 defaults=errors.value,
255 defaults=errors.value,
244 errors=errors.error_dict or {},
256 errors=errors.error_dict or {},
245 prefix_error=False,
257 prefix_error=False,
246 encoding="UTF-8",
258 encoding="UTF-8",
247 force_defaults=False
259 force_defaults=False
248 )
260 )
249 return Response(html)
261 return Response(html)
250
262
251 except Exception:
263 except Exception:
252 log.exception("Exception creating user group")
264 log.exception("Exception creating user group")
253 h.flash(_('Error occurred during creation of user group %s') \
265 h.flash(_('Error occurred during creation of user group %s') \
254 % user_group_name, category='error')
266 % user_group_name, category='error')
255 raise HTTPFound(h.route_path('user_groups_new'))
267 raise HTTPFound(h.route_path('user_groups_new'))
256
268
257 events.trigger(events.UserPermissionsChange([self._rhodecode_user.user_id]))
269 events.trigger(events.UserPermissionsChange([self._rhodecode_user.user_id]))
258 raise HTTPFound(
270 raise HTTPFound(
259 h.route_path('edit_user_group', user_group_id=user_group_id))
271 h.route_path('edit_user_group', user_group_id=user_group_id))
@@ -1,115 +1,115 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.mako"/>
2 <%inherit file="/base/base.mako"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('User groups administration')}
5 ${_('User groups administration')}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
13 ${h.link_to(_('Admin'),h.route_path('admin_home'))} &raquo; <span id="user_group_count">0</span>
13 ${h.link_to(_('Admin'),h.route_path('admin_home'))} &raquo; <span id="user_group_count">0</span>
14 </%def>
14 </%def>
15
15
16 <%def name="menu_bar_nav()">
16 <%def name="menu_bar_nav()">
17 ${self.menu_items(active='admin')}
17 ${self.menu_items(active='admin')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box">
21 <div class="box">
22
22
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 <ul class="links">
25 <ul class="links">
26 %if h.HasPermissionAny('hg.admin', 'hg.usergroup.create.true')():
26 %if h.HasPermissionAny('hg.admin', 'hg.usergroup.create.true')():
27 <li>
27 <li>
28 <a href="${h.route_path('user_groups_new')}" class="btn btn-small btn-success">${_(u'Add User Group')}</a>
28 <a href="${h.route_path('user_groups_new')}" class="btn btn-small btn-success">${_(u'Add User Group')}</a>
29 </li>
29 </li>
30 %endif
30 %endif
31 </ul>
31 </ul>
32 </div>
32 </div>
33
33
34 <div id="repos_list_wrap">
34 <div id="repos_list_wrap">
35 <table id="user_group_list_table" class="display"></table>
35 <table id="user_group_list_table" class="display"></table>
36 </div>
36 </div>
37
37
38 </div>
38 </div>
39 <script>
39 <script>
40 $(document).ready(function() {
40 $(document).ready(function() {
41 var $userGroupsListTable = $('#user_group_list_table');
41 var $userGroupsListTable = $('#user_group_list_table');
42
42
43 // user list
43 // user list
44 $userGroupsListTable.DataTable({
44 $userGroupsListTable.DataTable({
45 processing: true,
45 processing: true,
46 serverSide: true,
46 serverSide: true,
47 ajax: {
47 ajax: {
48 "url": "${h.route_path('user_groups_data')}",
48 "url": "${h.route_path('user_groups_data')}",
49 "dataSrc": function (json) {
49 "dataSrc": function (json) {
50 var filteredCount = json.recordsFiltered;
50 var filteredCount = json.recordsFiltered;
51 var filteredInactiveCount = json.recordsFilteredInactive;
51 var filteredInactiveCount = json.recordsFilteredInactive;
52 var totalInactive = json.recordsTotalInactive;
52 var totalInactive = json.recordsTotalInactive;
53 var total = json.recordsTotal;
53 var total = json.recordsTotal;
54
54
55 var _text = _gettext(
55 var _text = _gettext(
56 "{0} ({1} inactive) of {2} user groups ({3} inactive)").format(
56 "{0} ({1} inactive) of {2} user groups ({3} inactive)").format(
57 filteredCount, filteredInactiveCount, total, totalInactive);
57 filteredCount, filteredInactiveCount, total, totalInactive);
58
58
59 if (total === filteredCount) {
59 if (total === filteredCount) {
60 _text = _gettext(
60 _text = _gettext(
61 "{0} user groups ({1} inactive)").format(total, totalInactive);
61 "{0} user groups ({1} inactive)").format(total, totalInactive);
62 }
62 }
63 $('#user_group_count').text(_text);
63 $('#user_group_count').text(_text);
64 return json.data;
64 return json.data;
65 },
65 },
66 },
66 },
67
67
68 dom: 'rtp',
68 dom: 'rtp',
69 pageLength: ${c.visual.admin_grid_items},
69 pageLength: ${c.visual.admin_grid_items},
70 order: [[ 0, "asc" ]],
70 order: [[ 0, "asc" ]],
71 columns: [
71 columns: [
72 { data: {"_": "users_group_name",
72 { data: {"_": "users_group_name",
73 "sort": "users_group_name"}, title: "${_('Name')}", className: "td-componentname" },
73 "sort": "users_group_name"}, title: "${_('Name')}", className: "td-componentname" },
74 { data: {"_": "description",
74 { data: {"_": "description",
75 "sort": "description"}, title: "${_('Description')}", className: "td-description" },
75 "sort": "description"}, title: "${_('Description')}", className: "td-description" },
76 { data: {"_": "members",
76 { data: {"_": "members",
77 "sort": "members"}, title: "${_('Members')}", className: "td-number" },
77 "sort": "members"}, title: "${_('Members')}", className: "td-number" },
78 { data: {"_": "sync",
78 { data: {"_": "sync",
79 "sort": "sync"}, title: "${_('Sync')}", className: "td-sync" },
79 "sort": "sync"}, title: "${_('Sync')}", className: "td-sync" },
80 { data: {"_": "active",
80 { data: {"_": "active",
81 "sort": "active"}, title: "${_('Active')}", className: "td-active" },
81 "sort": "active"}, title: "${_('Active')}", className: "td-active" },
82 { data: {"_": "owner",
82 { data: {"_": "owner",
83 "sort": "owner"}, title: "${_('Owner')}", className: "td-user" },
83 "sort": "owner"}, title: "${_('Owner')}", className: "td-user" },
84 { data: {"_": "action",
84 { data: {"_": "action",
85 "sort": "action"}, title: "${_('Action')}", className: "td-action", orderable: false}
85 "sort": "action"}, title: "${_('Action')}", className: "td-action", orderable: false}
86 ],
86 ],
87 language: {
87 language: {
88 paginate: DEFAULT_GRID_PAGINATION,
88 paginate: DEFAULT_GRID_PAGINATION,
89 sProcessing: _gettext('loading...'),
89 sProcessing: _gettext('loading...'),
90 emptyTable: _gettext("No user groups available yet.")
90 emptyTable: _gettext("No user groups available yet.")
91 }
91 }
92 });
92 });
93
93
94 $userGroupsListTable.on('xhr.dt', function(e, settings, json, xhr){
94 $userGroupsListTable.on('xhr.dt', function(e, settings, json, xhr){
95 $userGroupsListTable.css('opacity', 1);
95 $userGroupsListTable.css('opacity', 1);
96 });
96 });
97
97
98 $userGroupsListTable.on('preXhr.dt', function(e, settings, data){
98 $userGroupsListTable.on('preXhr.dt', function(e, settings, data){
99 $userGroupsListTable.css('opacity', 0.3);
99 $userGroupsListTable.css('opacity', 0.3);
100 });
100 });
101
101
102 // filter
102 // filter
103 $('#q_filter').on('keyup',
103 $('#q_filter').on('keyup',
104 $.debounce(250, function() {
104 $.debounce(250, function() {
105 $('#user_group_list_table').DataTable().search(
105 $userGroupsListTable.DataTable().search(
106 $('#q_filter').val()
106 $('#q_filter').val()
107 ).draw();
107 ).draw();
108 })
108 })
109 );
109 );
110
110
111 });
111 });
112
112
113 </script>
113 </script>
114
114
115 </%def>
115 </%def>
General Comments 0
You need to be logged in to leave comments. Login now