##// END OF EJS Templates
users/user-groups: added context of what we're editing....
marcink -
r4232:60646747 stable
parent child Browse files
Show More
@@ -1,85 +1,89 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <%
4 4 elems = [
5 5 (_('User Group ID'), c.user_group.users_group_id, '', ''),
6 6 (_('Owner'), lambda:base.gravatar_with_user(c.user_group.user.email), '', ''),
7 7 (_('Created on'), h.format_date(c.user_group.created_on), '', '',),
8 8
9 9 (_('Members'), len(c.group_members_obj),'', [x for x in c.group_members_obj]),
10 10 (_('Automatic member sync'), 'Yes' if c.user_group.group_data.get('extern_type') else 'No', '', '',),
11 11
12 12 (_('Assigned to repositories'), len(c.group_to_repos),'', [x for x in c.group_to_repos]),
13 13 (_('Assigned to repo groups'), len(c.group_to_repo_groups), '', [x for x in c.group_to_repo_groups]),
14 14
15 15 (_('Assigned to review rules'), len(c.group_to_review_rules), '', [x for x in c.group_to_review_rules]),
16 16 ]
17 17 %>
18 18
19 19 <div class="panel panel-default">
20 20 <div class="panel-heading">
21 <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3>
21 <h3 class="panel-title">
22 <i class="icon-user-group" title="${_('User group')}"></i>
23 ${h.link_to_group(c.user_group.users_group_name)}
24 - ${_('Advanced')}
25 </h3>
22 26 </div>
23 27 <div class="panel-body">
24 28 ${base.dt_info_panel(elems)}
25 29 </div>
26 30
27 31 </div>
28 32
29 33 <div class="panel panel-default">
30 34 <div class="panel-heading">
31 35 <h3 class="panel-title">${_('Group members sync')}</h3>
32 36 </div>
33 37 <div class="panel-body">
34 38 <% sync_type = c.user_group.group_data.get('extern_type') %>
35 39
36 40 % if sync_type:
37 41 <p>
38 42 ${_('This group is set to be automatically synchronised.')}<br/>
39 43 ${_('This group synchronization was set by')}: <strong>${sync_type}</strong>
40 44 </p>
41 45 % else:
42 46 <p>
43 47 ${_('This group is not set to be automatically synchronised')}
44 48 </p>
45 49 % endif
46 50
47 51 <div>
48 52 ${h.secure_form(h.route_path('edit_user_group_advanced_sync', user_group_id=c.user_group.users_group_id), request=request)}
49 53 <div class="field">
50 54 <button class="btn btn-default" type="submit">
51 55 %if sync_type:
52 56 ${_('Disable synchronization')}
53 57 %else:
54 58 ${_('Enable synchronization')}
55 59 %endif
56 60 </button>
57 61 </div>
58 62 <div class="field">
59 63 <span class="help-block">
60 64 ${_('Users will be added or removed from this group when they authenticate with RhodeCode system, based on LDAP group membership. '
61 65 'This requires `LDAP+User group` authentication plugin to be configured and enabled. (EE only feature)')}
62 66 </span>
63 67 </div>
64 68 ${h.end_form()}
65 69 </div>
66 70
67 71 </div>
68 72 </div>
69 73
70 74
71 75 <div class="panel panel-danger">
72 76 <div class="panel-heading">
73 77 <h3 class="panel-title">${_('Delete User Group')}</h3>
74 78 </div>
75 79 <div class="panel-body">
76 80 ${h.secure_form(h.route_path('user_groups_delete', user_group_id=c.user_group.users_group_id), request=request)}
77 81 ${h.hidden('force', 1)}
78 82 <button class="btn btn-small btn-danger" type="submit"
79 83 onclick="return confirm('${_('Confirm to delete user group `%(ugroup)s` with all permission assignments') % {'ugroup': c.user_group.users_group_name}}');">
80 84 <i class="icon-remove"></i>
81 85 ${_('Delete This User Group')}
82 86 </button>
83 87 ${h.end_form()}
84 88 </div>
85 89 </div>
@@ -1,217 +1,221 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <div class="panel panel-default">
4 4 <div class="panel-heading">
5 <h3 class="panel-title">${_('User Group Permissions')}</h3>
5 <h3 class="panel-title">
6 <i class="icon-user-group" title="${_('User group')}"></i>
7 ${h.link_to_group(c.user_group.users_group_name)}
8 - ${_('Access Permissions')}
9 </h3>
6 10 </div>
7 11 <div class="panel-body">
8 12 ${h.secure_form(h.route_path('edit_user_group_perms_update', user_group_id=c.user_group.users_group_id), request=request)}
9 13 <table id="permissions_manage" class="rctable permissions">
10 14 <tr>
11 15 <th class="td-radio">${_('None')}</th>
12 16 <th class="td-radio">${_('Read')}</th>
13 17 <th class="td-radio">${_('Write')}</th>
14 18 <th class="td-radio">${_('Admin')}</th>
15 19 <th>${_('User/User Group')}</th>
16 20 <th class="td-action"></th>
17 21 <th class="td-action"></th>
18 22 </tr>
19 23 ## USERS
20 24 %for _user in c.user_group.permissions():
21 25 ## super admin/owner row
22 26 %if getattr(_user, 'admin_row', None) or getattr(_user, 'owner_row', None):
23 27 <tr class="perm_admin_row">
24 28 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.none', disabled="disabled")}</td>
25 29 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.read', disabled="disabled")}</td>
26 30 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.write', disabled="disabled")}</td>
27 31 <td class="td-radio">${h.radio('admin_perm_%s' % _user.user_id,'repository.admin', 'repository.admin', disabled="disabled")}</td>
28 32 <td class="td-user">
29 33 ${base.gravatar(_user.email, 16, user=_user, tooltip=True)}
30 34 <span class="user">
31 35 ${h.link_to_user(_user.username)}
32 36 %if getattr(_user, 'admin_row', None):
33 37 (${_('super-admin')})
34 38 %endif
35 39 %if getattr(_user, 'owner_row', None):
36 40 (${_('owner')})
37 41 %endif
38 42 </span>
39 43 </td>
40 44 <td></td>
41 45 <td class="quick_repo_menu">
42 46 % if c.rhodecode_user.is_admin:
43 47 <i class="icon-more"></i>
44 48 <div class="menu_items_container" style="display: none;">
45 49 <ul class="menu_items">
46 50 <li>
47 51 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='user-groups-permissions'))}
48 52 </li>
49 53 </ul>
50 54 </div>
51 55 % endif
52 56 </td>
53 57 </tr>
54 58 %else:
55 59 ##forbid revoking permission from yourself, except if you're an super admin
56 60 <tr>
57 61 %if c.rhodecode_user.user_id != _user.user_id or c.rhodecode_user.is_admin:
58 62 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.none')}</td>
59 63 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.read')}</td>
60 64 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.write')}</td>
61 65 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.admin')}</td>
62 66 <td class="td-user">
63 67 ${base.gravatar(_user.email, 16, user=_user, tooltip=True)}
64 68 <span class="user">
65 69 % if _user.username == h.DEFAULT_USER:
66 70 ${h.DEFAULT_USER}
67 71 % if _user.active:
68 72 <span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span>
69 73 % else:
70 74 <span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span>
71 75 % endif
72 76 % else:
73 77 ${h.link_to_user(_user.username)}
74 78 %if getattr(_user, 'duplicate_perm', None):
75 79 (${_('inactive duplicate')})
76 80 %endif
77 81 % endif
78 82 </span>
79 83 </td>
80 84 <td class="td-action">
81 85 %if _user.username != h.DEFAULT_USER:
82 86 <span class="btn btn-link btn-danger revoke_perm"
83 87 member="${_user.user_id}" member_type="user">
84 88 ${_('Remove')}
85 89 </span>
86 90 %endif
87 91 </td>
88 92 <td class="quick_repo_menu">
89 93 % if c.rhodecode_user.is_admin:
90 94 <i class="icon-more"></i>
91 95 <div class="menu_items_container" style="display: none;">
92 96 <ul class="menu_items">
93 97 <li>
94 98 % if _user.username == h.DEFAULT_USER:
95 99 ${h.link_to('show permissions', h.route_path('admin_permissions_overview', _anchor='user-groups-permissions'))}
96 100 % else:
97 101 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='user-groups-permissions'))}
98 102 % endif
99 103 </li>
100 104 </ul>
101 105 </div>
102 106 % endif
103 107 </td>
104 108 %else:
105 109 ## special case for currently logged-in user permissions, we make sure he cannot take his own permissions
106 110 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.none', disabled="disabled")}</td>
107 111 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.read', disabled="disabled")}</td>
108 112 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.write', disabled="disabled")}</td>
109 113 <td class="td-radio">${h.radio('u_perm_%s' % _user.user_id,'usergroup.admin', disabled="disabled")}</td>
110 114 <td class="td-user">
111 115 ${base.gravatar(_user.email, 16, user=_user, tooltip=True)}
112 116 <span class="user">
113 117 % if _user.username == h.DEFAULT_USER:
114 118 ${h.DEFAULT_USER}
115 119 % if _user.active:
116 120 <span class="user-perm-help-text"> - ${_('permission for other logged in and anonymous users')}</span>
117 121 % else:
118 122 <span class="user-perm-help-text"> - ${_('permission for other logged in users')}</span>
119 123 % endif
120 124 % else:
121 125 ${h.link_to_user(_user.username)}
122 126 %if getattr(_user, 'duplicate_perm', None):
123 127 (${_('inactive duplicate')})
124 128 %endif
125 129 % endif
126 130 <span class="user-perm-help-text">(${_('delegated admin')})</span>
127 131 </span>
128 132 </td>
129 133 <td></td>
130 134 <td class="quick_repo_menu">
131 135 % if c.rhodecode_user.is_admin:
132 136 <i class="icon-more"></i>
133 137 <div class="menu_items_container" style="display: none;">
134 138 <ul class="menu_items">
135 139 <li>
136 140 ${h.link_to('show permissions', h.route_path('edit_user_perms_summary', user_id=_user.user_id, _anchor='user-groups-permissions'))}
137 141 </li>
138 142 </ul>
139 143 </div>
140 144 % endif
141 145 </td>
142 146 %endif
143 147 </tr>
144 148 %endif
145 149 %endfor
146 150
147 151 ## USER GROUPS
148 152 %for _user_group in c.user_group.permission_user_groups(with_members=True):
149 153 <tr>
150 154 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.none')}</td>
151 155 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.read')}</td>
152 156 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.write')}</td>
153 157 <td class="td-radio">${h.radio('g_perm_%s' % _user_group.users_group_id,'usergroup.admin')}</td>
154 158 <td class="td-user">
155 159 <i class="icon-user-group"></i>
156 160 %if c.is_super_admin:
157 161 <a href="${h.route_path('edit_user_group',user_group_id=_user_group.users_group_id)}">
158 162 ${_user_group.users_group_name}
159 163 </a>
160 164 %else:
161 165 ${h.link_to_group(_user_group.users_group_name)}
162 166 %endif
163 167 (${_('members')}: ${len(_user_group.members)})
164 168 </td>
165 169 <td class="td-action">
166 170 <span class="btn btn-link btn-danger revoke_perm"
167 171 member="${_user_group.users_group_id}" member_type="user_group">
168 172 ${_('Remove')}
169 173 </span>
170 174 </td>
171 175 <td class="quick_repo_menu">
172 176 % if c.rhodecode_user.is_admin:
173 177 <i class="icon-more"></i>
174 178 <div class="menu_items_container" style="display: none;">
175 179 <ul class="menu_items">
176 180 <li>
177 181 ${h.link_to('show permissions', h.route_path('edit_user_group_perms_summary', user_group_id=_user_group.users_group_id, _anchor='user-groups-permissions'))}
178 182 </li>
179 183 </ul>
180 184 </div>
181 185 % endif
182 186 </td>
183 187 </tr>
184 188 %endfor
185 189 <tr class="new_members" id="add_perm_input"></tr>
186 190 <tr>
187 191 <td></td>
188 192 <td></td>
189 193 <td></td>
190 194 <td></td>
191 195 <td></td>
192 196 <td>
193 197 <span id="add_perm" class="link">
194 198 ${_('Add user/user group')}
195 199 </span>
196 200 </td>
197 201 <td></td>
198 202 </tr>
199 203 </table>
200 204
201 205 <div class="buttons">
202 206 ${h.submit('save',_('Save'),class_="btn btn-primary")}
203 207 ${h.reset('reset',_('Reset'),class_="btn btn-danger")}
204 208 </div>
205 209 ${h.end_form()}
206 210 </div>
207 211 </div>
208 212
209 213 <script type="text/javascript">
210 214 $('#add_perm').on('click', function(e){
211 215 addNewPermInput($(this), 'usergroup');
212 216 });
213 217 $('.revoke_perm').on('click', function(e){
214 218 markRevokePermInput($(this), 'usergroup');
215 219 });
216 220 quick_repo_menu()
217 221 </script>
@@ -1,186 +1,190 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%namespace name="base" file="/base/base.mako"/>
3 3
4 4 <div class="panel panel-default">
5 5 <div class="panel-heading">
6 <h3 class="panel-title">${_('User Group: %s') % c.user_group.users_group_name}</h3>
6 <h3 class="panel-title">
7 <i class="icon-user-group" title="${_('User group')}"></i>
8 ${h.link_to_group(c.user_group.users_group_name)}
9 - ${_('Settings')}
10 </h3>
7 11 </div>
8 12 <div class="panel-body">
9 13 ${h.secure_form(h.route_path('user_groups_update', user_group_id=c.user_group.users_group_id), id='edit_user_group', request=request)}
10 14 <div class="form">
11 15 <!-- fields -->
12 16 <div class="fields">
13 17 <div class="field">
14 18 <div class="label">
15 19 <label for="users_group_name">${_('Group name')}:</label>
16 20 </div>
17 21 <div class="input">
18 22 ${h.text('users_group_name',class_='medium')}
19 23 </div>
20 24 </div>
21 25
22 26 <div class="field badged-field">
23 27 <div class="label">
24 28 <label for="user">${_('Owner')}:</label>
25 29 </div>
26 30 <div class="input">
27 31 <div class="badge-input-container">
28 32 <div class="user-badge">
29 33 ${base.gravatar_with_user(c.user_group.user.email, show_disabled=not c.user_group.user.active)}
30 34 </div>
31 35 <div class="badge-input-wrap">
32 36 ${h.text('user', class_="medium", autocomplete="off")}
33 37 </div>
34 38 </div>
35 39 <form:error name="user"/>
36 40 <p class="help-block">${_('Change owner of this user group.')}</p>
37 41 </div>
38 42 </div>
39 43
40 44 <div class="field">
41 45 <div class="label label-textarea">
42 46 <label for="user_group_description">${_('Description')}:</label>
43 47 </div>
44 48 <div class="textarea textarea-small editor">
45 49 ${h.textarea('user_group_description',cols=23,rows=5,class_="medium")}
46 50 <span class="help-block">${_('Short, optional description for this user group.')}</span>
47 51 </div>
48 52 </div>
49 53 <div class="field">
50 54 <div class="label label-checkbox">
51 55 <label for="users_group_active">${_('Active')}:</label>
52 56 </div>
53 57 <div class="checkboxes">
54 58 ${h.checkbox('users_group_active',value=True)}
55 59 </div>
56 60 </div>
57 61
58 62 <div class="field">
59 63 <div class="label label-checkbox">
60 64 <label for="users_group_active">${_('Add members')}:</label>
61 65 </div>
62 66 <div class="input">
63 67 ${h.text('user_group_add_members', placeholder="user/usergroup", class_="medium")}
64 68 </div>
65 69 </div>
66 70
67 71 <input type="hidden" name="__start__" value="user_group_members:sequence"/>
68 72 <table id="group_members_placeholder" class="rctable group_members">
69 73 <tr>
70 74 <th>${_('Username')}</th>
71 75 <th>${_('Action')}</th>
72 76 </tr>
73 77
74 78 % if c.group_members_obj:
75 79 % for user in c.group_members_obj:
76 80 <tr>
77 81 <td id="member_user_${user.user_id}" class="td-author">
78 82 <div class="group_member">
79 83 ${base.gravatar(user.email, 16, user=user, tooltip=True)}
80 84 <span class="username user">${h.link_to(h.person(user), h.route_path('user_edit',user_id=user.user_id))}</span>
81 85 <input type="hidden" name="__start__" value="member:mapping">
82 86 <input type="hidden" name="member_user_id" value="${user.user_id}">
83 87 <input type="hidden" name="type" value="existing" id="member_${user.user_id}">
84 88 <input type="hidden" name="__end__" value="member:mapping">
85 89 </div>
86 90 </td>
87 91 <td class="">
88 92 <div class="usergroup_member_remove action_button" onclick="removeUserGroupMember(${user.user_id}, true)" style="visibility: visible;">
89 93 <i class="icon-remove"></i>
90 94 </div>
91 95 </td>
92 96 </tr>
93 97 % endfor
94 98
95 99 % else:
96 100 <tr><td colspan="2">${_('No members yet')}</td></tr>
97 101 % endif
98 102 </table>
99 103 <input type="hidden" name="__end__" value="user_group_members:sequence"/>
100 104
101 105 <div class="buttons">
102 106 ${h.submit('Save',_('Save'),class_="btn")}
103 107 </div>
104 108 </div>
105 109 </div>
106 110 ${h.end_form()}
107 111 </div>
108 112 </div>
109 113 <script>
110 114 $(document).ready(function(){
111 115 $("#group_parent_id").select2({
112 116 'containerCssClass': "drop-menu",
113 117 'dropdownCssClass': "drop-menu-dropdown",
114 118 'dropdownAutoWidth': true
115 119 });
116 120
117 121 removeUserGroupMember = function(userId){
118 122 $('#member_'+userId).val('remove');
119 123 $('#member_user_'+userId).addClass('to-delete');
120 124 };
121 125
122 126 $('#user_group_add_members').autocomplete({
123 127 serviceUrl: pyroutes.url('user_autocomplete_data'),
124 128 minChars:2,
125 129 maxHeight:400,
126 130 width:300,
127 131 deferRequestBy: 300, //miliseconds
128 132 showNoSuggestionNotice: true,
129 133 params: { user_groups:true },
130 134 formatResult: autocompleteFormatResult,
131 135 lookupFilter: autocompleteFilterResult,
132 136 onSelect: function(element, suggestion){
133 137
134 138 function addMember(user, fromUserGroup) {
135 139 var gravatar = user.icon_link;
136 140 var username = user.value_display;
137 141 var userLink = pyroutes.url('user_edit', {"user_id": user.id});
138 142 var uid = user.id;
139 143
140 144 if (fromUserGroup) {
141 145 username = username +" "+ _gettext('(from usergroup {0})'.format(fromUserGroup))
142 146 }
143 147
144 148 var elem = $(
145 149 ('<tr>'+
146 150 '<td id="member_user_{6}" class="td-author td-author-new-entry">'+
147 151 '<div class="group_member">'+
148 152 '<img class="gravatar" src="{0}" height="16" width="16">'+
149 153 '<span class="username user"><a href="{1}">{2}</a></span>'+
150 154 '<input type="hidden" name="__start__" value="member:mapping">'+
151 155 '<input type="hidden" name="member_user_id" value="{3}">'+
152 156 '<input type="hidden" name="type" value="new" id="member_{4}">'+
153 157 '<input type="hidden" name="__end__" value="member:mapping">'+
154 158 '</div>'+
155 159 '</td>'+
156 160 '<td class="td-author-new-entry">'+
157 161 '<div class="usergroup_member_remove action_button" onclick="removeUserGroupMember({5}, true)" style="visibility: visible;">'+
158 162 '<i class="icon-remove"></i>'+
159 163 '</div>'+
160 164 '</td>'+
161 165 '</tr>').format(gravatar, userLink, username,
162 166 uid, uid, uid, uid)
163 167 );
164 168 $('#group_members_placeholder').append(elem)
165 169 }
166 170
167 171 if (suggestion.value_type == 'user_group') {
168 172 $.getJSON(
169 173 pyroutes.url('user_group_members_data',
170 174 {'user_group_id': suggestion.id}),
171 175 function(data) {
172 176 $.each(data.members, function(idx, user) {
173 177 addMember(user, suggestion.value)
174 178 });
175 179 }
176 180 );
177 181 } else if (suggestion.value_type == 'user') {
178 182 addMember(suggestion, null);
179 183 }
180 184 }
181 185 });
182 186
183 187
184 188 UsersAutoComplete('user', '${c.rhodecode_user.user_id}');
185 189 })
186 190 </script>
@@ -1,195 +1,198 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <%
4 4 elems = [
5 5 (_('User ID'), c.user.user_id, '', ''),
6 6 (_('Created on'), h.format_date(c.user.created_on), '', ''),
7 7 (_('Source of Record'), c.user.extern_type, '', ''),
8 8
9 9 (_('Last login'), c.user.last_login or '-', '', ''),
10 10 (_('Last activity'), c.user.last_activity, '', ''),
11 11
12 12 (_('Repositories'), len(c.user.repositories), '', [x.repo_name for x in c.user.repositories]),
13 13 (_('Repository groups'), len(c.user.repository_groups), '', [x.group_name for x in c.user.repository_groups]),
14 14 (_('User groups'), len(c.user.user_groups), '', [x.users_group_name for x in c.user.user_groups]),
15 15
16 16 (_('Owned Artifacts'), len(c.user.artifacts), '', [x.file_uid for x in c.user.artifacts]),
17 17
18 18 (_('Reviewer of pull requests'), len(c.user.reviewer_pull_requests), '', ['Pull Request #{}'.format(x.pull_request.pull_request_id) for x in c.user.reviewer_pull_requests]),
19 19 (_('Assigned to review rules'), len(c.user_to_review_rules), '', [x for x in c.user_to_review_rules]),
20 20
21 21 (_('Member of User groups'), len(c.user.group_member), '', [x.users_group.users_group_name for x in c.user.group_member]),
22 22 (_('Force password change'), c.user.user_data.get('force_password_change', 'False'), '', ''),
23 23 ]
24 24 %>
25 25
26 26 <div class="panel panel-default">
27 27 <div class="panel-heading">
28 <h3 class="panel-title">${_('User: {}').format(c.user.username)}</h3>
28 <h3 class="panel-title">
29 ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')}
30 &nbsp;- ${_('Access Permissions')}
31 </h3>
29 32 </div>
30 33 <div class="panel-body">
31 34 <table class="rctable">
32 35 <tr>
33 36 <th>Name</th>
34 37 <th>Value</th>
35 38 <th>Action</th>
36 39 </tr>
37 40 % for elem in elems:
38 41 ${base.tr_info_entry(elem)}
39 42 % endfor
40 43 </table>
41 44 </div>
42 45 </div>
43 46
44 47 <div class="panel panel-default">
45 48 <div class="panel-heading">
46 49 <h3 class="panel-title">${_('Force Password Reset')}</h3>
47 50 </div>
48 51 <div class="panel-body">
49 52 ${h.secure_form(h.route_path('user_disable_force_password_reset', user_id=c.user.user_id), request=request)}
50 53 <div class="field">
51 54 <button class="btn btn-default" type="submit">
52 55 <i class="icon-unlock"></i> ${_('Disable forced password reset')}
53 56 </button>
54 57 </div>
55 58 <div class="field">
56 59 <span class="help-block">
57 60 ${_("Clear the forced password change flag.")}
58 61 </span>
59 62 </div>
60 63 ${h.end_form()}
61 64
62 65 ${h.secure_form(h.route_path('user_enable_force_password_reset', user_id=c.user.user_id), request=request)}
63 66 <div class="field">
64 67 <button class="btn btn-default" type="submit" onclick="return confirm('${_('Confirm to enable forced password change')}');">
65 68 <i class="icon-lock"></i> ${_('Enable forced password reset')}
66 69 </button>
67 70 </div>
68 71 <div class="field">
69 72 <span class="help-block">
70 73 ${_("When this is enabled user will have to change they password when they next use RhodeCode system. This will also forbid vcs operations until someone makes a password change in the web interface")}
71 74 </span>
72 75 </div>
73 76 ${h.end_form()}
74 77
75 78 </div>
76 79 </div>
77 80
78 81 <div class="panel panel-default">
79 82 <div class="panel-heading">
80 83 <h3 class="panel-title">${_('Personal Repository Group')}</h3>
81 84 </div>
82 85 <div class="panel-body">
83 86 ${h.secure_form(h.route_path('user_create_personal_repo_group', user_id=c.user.user_id), request=request)}
84 87
85 88 %if c.personal_repo_group:
86 89 <div class="panel-body-title-text">${_('Users personal repository group')} : ${h.link_to(c.personal_repo_group.group_name, h.route_path('repo_group_home', repo_group_name=c.personal_repo_group.group_name))}</div>
87 90 %else:
88 91 <div class="panel-body-title-text">
89 92 ${_('This user currently does not have a personal repository group')}
90 93 <br/>
91 94 ${_('New group will be created at: `/%(path)s`') % {'path': c.personal_repo_group_name}}
92 95 </div>
93 96 %endif
94 97 <button class="btn btn-default" type="submit" ${'disabled="disabled"' if c.personal_repo_group else ''}>
95 98 <i class="icon-repo-group"></i>
96 99 ${_('Create personal repository group')}
97 100 </button>
98 101 ${h.end_form()}
99 102 </div>
100 103 </div>
101 104
102 105
103 106 <div class="panel panel-danger">
104 107 <div class="panel-heading">
105 108 <h3 class="panel-title">${_('Delete User')}</h3>
106 109 </div>
107 110 <div class="panel-body">
108 111 ${h.secure_form(h.route_path('user_delete', user_id=c.user.user_id), request=request)}
109 112
110 113 <table class="display rctable">
111 114 <tr>
112 115 <td>
113 116 ${_ungettext('This user owns %s repository.', 'This user owns %s repositories.', len(c.user.repositories)) % len(c.user.repositories)}
114 117 </td>
115 118 <td>
116 119 <input type="radio" id="user_repos_1" name="user_repos" value="detach" checked="checked" ${'disabled=1' if len(c.user.repositories) == 0 else ''} /> <label for="user_repos_1">${_('Detach repositories')}</label>
117 120 </td>
118 121 <td>
119 122 <input type="radio" id="user_repos_2" name="user_repos" value="delete" ${'disabled=1' if len(c.user.repositories) == 0 else ''} /> <label for="user_repos_2">${_('Delete repositories')}</label>
120 123 </td>
121 124 </tr>
122 125
123 126 <tr>
124 127 <td>
125 128 ${_ungettext('This user owns %s repository group.', 'This user owns %s repository groups.', len(c.user.repository_groups)) % len(c.user.repository_groups)}
126 129 </td>
127 130 <td>
128 131 <input type="radio" id="user_repo_groups_1" name="user_repo_groups" value="detach" checked="checked" ${'disabled=1' if len(c.user.repository_groups) == 0 else ''} /> <label for="user_repo_groups_1">${_('Detach repository groups')}</label>
129 132 </td>
130 133 <td>
131 134 <input type="radio" id="user_repo_groups_2" name="user_repo_groups" value="delete" ${'disabled=1' if len(c.user.repository_groups) == 0 else ''}/> <label for="user_repo_groups_2">${_('Delete repositories')}</label>
132 135 </td>
133 136 </tr>
134 137
135 138 <tr>
136 139 <td>
137 140 ${_ungettext('This user owns %s user group.', 'This user owns %s user groups.', len(c.user.user_groups)) % len(c.user.user_groups)}
138 141 </td>
139 142 <td>
140 143 <input type="radio" id="user_user_groups_1" name="user_user_groups" value="detach" checked="checked" ${'disabled=1' if len(c.user.user_groups) == 0 else ''}/> <label for="user_user_groups_1">${_('Detach user groups')}</label>
141 144 </td>
142 145 <td>
143 146 <input type="radio" id="user_user_groups_2" name="user_user_groups" value="delete" ${'disabled=1' if len(c.user.user_groups) == 0 else ''}/> <label for="user_user_groups_2">${_('Delete repositories')}</label>
144 147 </td>
145 148 </tr>
146 149
147 150 <tr>
148 151 <td>
149 152 ${_ungettext('This user owns %s artifact.', 'This user owns %s artifacts.', len(c.user.artifacts)) % len(c.user.artifacts)}
150 153 </td>
151 154 <td>
152 155 <input type="radio" id="user_artifacts_1" name="user_artifacts" value="detach" checked="checked" ${'disabled=1' if len(c.user.artifacts) == 0 else ''}/> <label for="user_artifacts_1">${_('Detach Artifacts')}</label>
153 156 </td>
154 157 <td>
155 158 <input type="radio" id="user_artifacts_2" name="user_artifacts" value="delete" ${'disabled=1' if len(c.user.artifacts) == 0 else ''}/> <label for="user_artifacts_2">${_('Delete Artifacts')}</label>
156 159 </td>
157 160 </tr>
158 161
159 162 </table>
160 163 <div style="margin: 0 0 20px 0" class="fake-space"></div>
161 164 <div class="pull-left">
162 165 % if len(c.user.repositories) > 0 or len(c.user.repository_groups) > 0 or len(c.user.user_groups) > 0:
163 166 % endif
164 167
165 168 <span style="padding: 0 5px 0 0">${_('New owner for detached objects')}:</span>
166 169 <div class="pull-right">${base.gravatar_with_user(c.first_admin.email, 16)}</div>
167 170 </div>
168 171 <div style="clear: both">
169 172
170 173 <div>
171 174 <p class="help-block">
172 175 ${_("When selecting the detach option, the depending objects owned by this user will be assigned to the above user.")}
173 176 <br/>
174 177 ${_("The delete option will delete the user and all his owned objects!")}
175 178 </p>
176 179 </div>
177 180
178 181 % if c.can_delete_user_message:
179 182 <p class="pre-formatting">${c.can_delete_user_message}</p>
180 183 % endif
181 184 </div>
182 185
183 186 <div style="margin: 0 0 20px 0" class="fake-space"></div>
184 187
185 188 <div class="field">
186 189 <button class="btn btn-small btn-danger" type="submit"
187 190 onclick="return confirm('${_('Confirm to delete this user: %s') % c.user.username}');"
188 191 ${"disabled" if not c.can_delete_user else ""}>
189 192 ${_('Delete this user')}
190 193 </button>
191 194 </div>
192 195
193 196 ${h.end_form()}
194 197 </div>
195 198 </div>
@@ -1,25 +1,27 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%namespace name="base" file="/base/base.mako"/>
3 3
4 4
5 5 <div class="panel panel-default">
6 6 <div class="panel-heading">
7 <h3 class="panel-title">${_('User Audit Logs')} -
8 ${_ungettext('%s entry', '%s entries', c.audit_logs.item_count) % (c.audit_logs.item_count)}
7 <h3 class="panel-title">
8 ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')}
9 &nbsp;- ${_('Audit Logs')}
10 (${_ungettext('%s entry', '%s entries', c.audit_logs.item_count) % (c.audit_logs.item_count)})
9 11 </h3>
10 12 <a href="${h.route_path('edit_user_audit_logs_download', user_id=c.user.user_id)}" class="panel-edit">${_('Download as JSON')}</a>
11 13 </div>
12 14 <div class="panel-body">
13 15
14 16 ${h.form(None, id_="filter_form", method="get")}
15 17 <input class="q_filter_box ${'' if c.filter_term else 'initial'}" id="j_filter" size="15" type="text" name="filter" value="${c.filter_term or ''}" placeholder="${_('audit filter...')}"/>
16 18 <input type='submit' value="${_('filter')}" class="btn" />
17 19 ${h.end_form()}
18 20
19 21 <p class="filterexample" style="position: inherit" onclick="$('#search-help').toggle()">${_('Example Queries')}</p>
20 22 <pre id="search-help" style="display: none">${h.tooltip(h.journal_filter_help(request))}</pre>
21 23
22 24 <%include file="/admin/admin_log_base.mako" />
23 25
24 26 </div>
25 27 </div>
@@ -1,191 +1,196 b''
1 <%namespace name="base" file="/base/base.mako"/>
2
1 3 <div class="panel panel-default">
2 4 <div class="panel-heading">
3 <h3 class="panel-title">${_('Authentication Tokens')}</h3>
5 <h3 class="panel-title">
6 ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')}
7 &nbsp;- ${_('Authentication Tokens')}
8 </h3>
4 9 </div>
5 10 <div class="panel-body">
6 11 <div class="apikeys_wrap">
7 12 <p>
8 13 ${_('Authentication tokens can be used to interact with the API, or VCS-over-http. '
9 14 'Each token can have a role. Token with a role can be used only in given context, '
10 15 'e.g. VCS tokens can be used together with the authtoken auth plugin for git/hg/svn operations only.')}
11 16 </p>
12 17 <table class="rctable auth_tokens">
13 18 <tr>
14 19 <th>${_('Token')}</th>
15 20 <th>${_('Description')}</th>
16 21 <th>${_('Role')}</th>
17 22 <th>${_('Repository Scope')}</th>
18 23 <th>${_('Expiration')}</th>
19 24 <th>${_('Action')}</th>
20 25 </tr>
21 26 %if c.user_auth_tokens:
22 27 %for auth_token in c.user_auth_tokens:
23 28 <tr class="${('expired' if auth_token.expired else '')}">
24 29 <td class="truncate-wrap td-authtoken">
25 30 <div class="user_auth_tokens truncate autoexpand">
26 31 <code>${auth_token.api_key}</code>
27 32 </div>
28 33 </td>
29 34 <td class="td-wrap">${auth_token.description}</td>
30 35 <td class="td-tags">
31 36 <span class="tag disabled">${auth_token.role_humanized}</span>
32 37 </td>
33 38 <td class="td">${auth_token.scope_humanized}</td>
34 39 <td class="td-exp">
35 40 %if auth_token.expires == -1:
36 41 ${_('never')}
37 42 %else:
38 43 %if auth_token.expired:
39 44 <span style="text-decoration: line-through">${h.age_component(h.time_to_utcdatetime(auth_token.expires))}</span>
40 45 %else:
41 46 ${h.age_component(h.time_to_utcdatetime(auth_token.expires))}
42 47 %endif
43 48 %endif
44 49 </td>
45 50 <td class="td-action">
46 51 ${h.secure_form(h.route_path('edit_user_auth_tokens_delete', user_id=c.user.user_id), request=request)}
47 52 ${h.hidden('del_auth_token', auth_token.user_api_key_id)}
48 53 <button class="btn btn-link btn-danger" type="submit"
49 54 onclick="return confirm('${_('Confirm to remove this auth token: %s') % auth_token.token_obfuscated}');">
50 55 ${_('Delete')}
51 56 </button>
52 57 ${h.end_form()}
53 58 </td>
54 59 </tr>
55 60 %endfor
56 61 %else:
57 62 <tr><td><div class="ip">${_('No additional auth tokens specified')}</div></td></tr>
58 63 %endif
59 64 </table>
60 65 </div>
61 66
62 67 <div class="user_auth_tokens">
63 68 ${h.secure_form(h.route_path('edit_user_auth_tokens_add', user_id=c.user.user_id), request=request)}
64 69 <div class="form form-vertical">
65 70 <!-- fields -->
66 71 <div class="fields">
67 72 <div class="field">
68 73 <div class="label">
69 74 <label for="new_email">${_('New authentication token')}:</label>
70 75 </div>
71 76 <div class="input">
72 77 ${h.text('description', class_='medium', placeholder=_('Description'))}
73 78 ${h.hidden('lifetime')}
74 79 ${h.select('role', '', c.role_options)}
75 80
76 81 % if c.allow_scoped_tokens:
77 82 ${h.hidden('scope_repo_id')}
78 83 % else:
79 84 ${h.select('scope_repo_id_disabled', '', ['Scopes available in EE edition'], disabled='disabled')}
80 85 % endif
81 86 </div>
82 87 <p class="help-block">
83 88 ${_('Repository scope works only with tokens with VCS type.')}
84 89 </p>
85 90 </div>
86 91 <div class="buttons">
87 92 ${h.submit('save',_('Add'),class_="btn")}
88 93 ${h.reset('reset',_('Reset'),class_="btn")}
89 94 </div>
90 95 </div>
91 96 </div>
92 97 ${h.end_form()}
93 98 </div>
94 99 </div>
95 100 </div>
96 101
97 102 <script>
98 103
99 104 $(document).ready(function(){
100 105
101 106 var select2Options = {
102 107 'containerCssClass': "drop-menu",
103 108 'dropdownCssClass': "drop-menu-dropdown",
104 109 'dropdownAutoWidth': true
105 110 };
106 111 $("#role").select2(select2Options);
107 112
108 113 var preloadData = {
109 114 results: [
110 115 % for entry in c.lifetime_values:
111 116 {id:${entry[0]}, text:"${entry[1]}"}${'' if loop.last else ','}
112 117 % endfor
113 118 ]
114 119 };
115 120
116 121 $("#lifetime").select2({
117 122 containerCssClass: "drop-menu",
118 123 dropdownCssClass: "drop-menu-dropdown",
119 124 dropdownAutoWidth: true,
120 125 data: preloadData,
121 126 placeholder: "${_('Select or enter expiration date')}",
122 127 query: function(query) {
123 128 feedLifetimeOptions(query, preloadData);
124 129 }
125 130 });
126 131
127 132
128 133 var repoFilter = function(data) {
129 134 var results = [];
130 135
131 136 if (!data.results[0]) {
132 137 return data
133 138 }
134 139
135 140 $.each(data.results[0].children, function() {
136 141 // replace name to ID for submision
137 142 this.id = this.repo_id;
138 143 results.push(this);
139 144 });
140 145
141 146 data.results[0].children = results;
142 147 return data;
143 148 };
144 149
145 150 $("#scope_repo_id_disabled").select2(select2Options);
146 151
147 152 var selectVcsScope = function() {
148 153 // select vcs scope and disable input
149 154 $("#role").select2("val", "${c.role_vcs}").trigger('change');
150 155 $("#role").select2("readonly", true)
151 156 };
152 157
153 158 $("#scope_repo_id").select2({
154 159 cachedDataSource: {},
155 160 minimumInputLength: 2,
156 161 placeholder: "${_('repository scope')}",
157 162 dropdownAutoWidth: true,
158 163 containerCssClass: "drop-menu",
159 164 dropdownCssClass: "drop-menu-dropdown",
160 165 formatResult: formatRepoResult,
161 166 query: $.debounce(250, function(query){
162 167 self = this;
163 168 var cacheKey = query.term;
164 169 var cachedData = self.cachedDataSource[cacheKey];
165 170
166 171 if (cachedData) {
167 172 query.callback({results: cachedData.results});
168 173 } else {
169 174 $.ajax({
170 175 url: pyroutes.url('repo_list_data'),
171 176 data: {'query': query.term},
172 177 dataType: 'json',
173 178 type: 'GET',
174 179 success: function(data) {
175 180 data = repoFilter(data);
176 181 self.cachedDataSource[cacheKey] = data;
177 182 query.callback({results: data.results});
178 183 },
179 184 error: function(data, textStatus, errorThrown) {
180 185 alert("Error while fetching entries.\nError code {0} ({1}).".format(data.status, data.statusText));
181 186 }
182 187 })
183 188 }
184 189 })
185 190 });
186 191 $("#scope_repo_id").on('select2-selecting', function(e){
187 192 selectVcsScope()
188 193 });
189 194
190 195 });
191 196 </script>
@@ -1,41 +1,44 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <div class="panel panel-default">
4 4 <div class="panel-heading">
5 <h3 class="panel-title">${_('Caches')}</h3>
5 <h3 class="panel-title">
6 ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')}
7 &nbsp;- ${_('Caches')}
8 </h3>
6 9 </div>
7 10 <div class="panel-body">
8 11 <p>
9 12 Cache keys used for storing cached values of user permissions and authentication plugin cache.
10 13 Invalidating the cache will remove those entries.
11 14 </p>
12 15
13 16 <pre>
14 17 region: ${c.region.name}
15 18 backend: ${c.region.actual_backend.__class__}
16 19 store: ${c.region.actual_backend.get_store()}
17 20
18 21 % if c.user_keys:
19 22 ${len(c.user_keys)} <a href="#showKeys" onclick="$('#show-keys').toggle()">${_('Show all')}</a>
20 23 <span id="show-keys" style="display: none">
21 24 % for k in c.user_keys:
22 25 - ${k}
23 26 % endfor
24 27 </span>
25 28 % else:
26 29 NO KEYS FOUND
27 30 % endif
28 31 </pre>
29 32 <p></p>
30 33 ${h.secure_form(h.route_path('edit_user_caches_update', user_id=c.user.user_id), request=request)}
31 34 <div class="form">
32 35 <div class="fields">
33 36 ${h.submit('reset_cache_%s' % c.user.user_id, _('Invalidate user cache'),class_="btn btn-small",onclick="return confirm('"+_('Confirm to invalidate user cache')+"');")}
34 37 </div>
35 38 </div>
36 39 ${h.end_form()}
37 40
38 41 </div>
39 42 </div>
40 43
41 44
@@ -1,71 +1,74 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <div class="panel panel-default">
4 4 <div class="panel-heading">
5 <h3 class="panel-title">${_('Additional Email Addresses')}</h3>
5 <h3 class="panel-title">
6 ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')}
7 &nbsp;- ${_('Additional Email Addresses')}
8 </h3>
6 9 </div>
7 10 <div class="panel-body">
8 11 <div class="emails_wrap">
9 12 <table class="rctable account_emails useremails">
10 13 <tr>
11 14 <td class="td-user">
12 15 ${base.gravatar(c.user.email, 16)}
13 16 <span class="user email">${c.user.email}</span>
14 17 </td>
15 18 <td class="td-tags">
16 19 <span class="tag">${_('Primary')}</span>
17 20 </td>
18 21 </tr>
19 22 %if c.user_email_map:
20 23 %for em in c.user_email_map:
21 24 <tr>
22 25 <td class="td-user">
23 26 ${base.gravatar(em.email, 16)}
24 27 <span class="user email">${em.email}</span>
25 28 </td>
26 29 <td class="td-action">
27 30 ${h.secure_form(h.route_path('edit_user_emails_delete', user_id=c.user.user_id), request=request)}
28 31 ${h.hidden('del_email_id', em.email_id)}
29 32 <button class="btn btn-link btn-danger" type="submit"
30 33 onclick="return confirm('${_('Confirm to delete this email: %s') % em.email}');">
31 34 ${_('Delete')}
32 35 </button>
33 36 ${h.end_form()}
34 37 </td>
35 38 </tr>
36 39 %endfor
37 40 %else:
38 41 <tr class="noborder">
39 42 <td colspan="3">
40 43 <div class="td-email">
41 44 ${_('No additional emails specified')}
42 45 </div>
43 46 </td>
44 47 </tr>
45 48 %endif
46 49 </table>
47 50 </div>
48 51
49 52 ${h.secure_form(h.route_path('edit_user_emails_add', user_id=c.user.user_id), request=request)}
50 53 <div class="form">
51 54 <!-- fields -->
52 55 <div class="fields">
53 56 <div class="field">
54 57 <div class="label">
55 58 <label for="new_email">${_('New email address')}:</label>
56 59 </div>
57 60 <div class="input">
58 61 ${h.text('new_email', class_='medium')}
59 62 </div>
60 63 </div>
61 64 <div class="buttons">
62 65 ${h.submit('save',_('Add'),class_="btn btn-small")}
63 66 ${h.reset('reset',_('Reset'),class_="btn btn-small")}
64 67 </div>
65 68 </div>
66 69 </div>
67 70 ${h.end_form()}
68 71 </div>
69 72 </div>
70 73
71 74
@@ -1,147 +1,150 b''
1 1 ## -*- coding: utf-8 -*-
2
2 <%namespace name="base" file="/base/base.mako"/>
3 3
4 4 <div class="panel panel-default">
5 5 <div class="panel-heading">
6 <h3 class="panel-title">${_('User groups administration')}</h3>
6 <h3 class="panel-title">
7 ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')}
8 &nbsp;- ${_('User groups administration')}
9 </h3>
7 10 </div>
8 11 <div class="panel-body">
9 12 <div class="fields">
10 13 <div class="field">
11 14 <div class="label label-checkbox">
12 15 <label for="users_group_active">${_('Add `%s` to user group') % c.user.username}:</label>
13 16 </div>
14 17 <div class="input">
15 18 ${h.text('add_user_to_group', placeholder="user group name", class_="medium")}
16 19 </div>
17 20
18 21 </div>
19 22 </div>
20 23
21 24 <div class="groups_management">
22 25 ${h.secure_form(h.route_path('edit_user_groups_management_updates', user_id=c.user.user_id), request=request)}
23 26 <div id="repos_list_wrap">
24 27 <table id="user_group_list_table" class="display"></table>
25 28 </div>
26 29 <div class="buttons">
27 30 ${h.submit('save',_('Save'),class_="btn")}
28 31 </div>
29 32 ${h.end_form()}
30 33 </div>
31 34 </div>
32 35 </div>
33 36 <script>
34 37 var api;
35 38 $(document).ready(function() {
36 39
37 40 var get_datatable_count = function(){
38 41 $('#user_group_count').text(api.page.info().recordsDisplay);
39 42 };
40 43
41 44 $('#user_group_list_table').on('click', 'a.editor_remove', function (e) {
42 45 e.preventDefault();
43 46 var row = api.row($(this).closest('tr'));
44 47 row.remove().draw();
45 48 } );
46 49
47 50 $('#user_group_list_table').DataTable({
48 51 data: ${c.groups|n},
49 52 dom: 'rtp',
50 53 pageLength: ${c.visual.admin_grid_items},
51 54 order: [[ 0, "asc" ]],
52 55 columns: [
53 56 { data: {"_": "group_name",
54 57 "sort": "group_name"}, title: "${_('Name')}", className: "td-componentname," ,
55 58 render: function (data,type,full,meta)
56 59 {return '<div><i class="icon-user-group" title="User group">'+data+'</i></div>'}},
57 60
58 61 { data: {"_": "group_description",
59 62 "sort": "group_description"}, title: "${_('Description')}", className: "td-description" },
60 63 { data: {"_": "users_group_id"}, className: "td-user",
61 64 render: function (data,type,full,meta)
62 65 {return '<input type="hidden" name="users_group_id" value="'+data+'">'}},
63 66 { data: {"_": "active",
64 67 "sort": "active"}, title: "${_('Active')}", className: "td-active"},
65 68 { data: {"_": "owner_data"}, title: "${_('Owner')}", className: "td-user",
66 69 render: function (data,type,full,meta)
67 70 {return '<div class="rc-user tooltip">'+
68 71 '<img class="gravatar" src="'+ data.owner_icon +'" height="16" width="16">'+
69 72 data.owner +'</div>'
70 73 }
71 74 },
72 75 { data: null,
73 76 title: "${_('Action')}",
74 77 className: "td-action",
75 78 defaultContent: '-'
76 79 }
77 80 ],
78 81 language: {
79 82 paginate: DEFAULT_GRID_PAGINATION,
80 83 emptyTable: _gettext("No user groups available yet.")
81 84 },
82 85 "initComplete": function( settings, json ) {
83 86 var data_grid = $('#user_group_list_table').dataTable();
84 87 api = data_grid.api();
85 88 get_datatable_count();
86 89 }
87 90 });
88 91
89 92 // update the counter when doing search
90 93 $('#user_group_list_table').on( 'search.dt', function (e,settings) {
91 94 get_datatable_count();
92 95 });
93 96
94 97 // filter, filter both grids
95 98 $('#q_filter').on( 'keyup', function () {
96 99 var user_api = $('#user_group_list_table').dataTable().api();
97 100 user_api
98 101 .columns(0)
99 102 .search(this.value)
100 103 .draw();
101 104 });
102 105
103 106 // refilter table if page load via back button
104 107 $("#q_filter").trigger('keyup');
105 108
106 109 });
107 110
108 111 $('#language').select2({
109 112 'containerCssClass': "drop-menu",
110 113 'dropdownCssClass': "drop-menu-dropdown",
111 114 'dropdownAutoWidth': true
112 115 });
113 116
114 117
115 118
116 119 $(document).ready(function(){
117 120 $("#group_parent_id").select2({
118 121 'containerCssClass': "drop-menu",
119 122 'dropdownCssClass': "drop-menu-dropdown",
120 123 'dropdownAutoWidth': true
121 124 });
122 125
123 126 $('#add_user_to_group').autocomplete({
124 127 serviceUrl: pyroutes.url('user_group_autocomplete_data'),
125 128 minChars:2,
126 129 maxHeight:400,
127 130 width:300,
128 131 deferRequestBy: 300, //miliseconds
129 132 showNoSuggestionNotice: true,
130 133 params: { user_groups:true },
131 134 formatResult: autocompleteFormatResult,
132 135 lookupFilter: autocompleteFilterResult,
133 136 onSelect: function(element, suggestion){
134 137 var owner = {owner_icon: suggestion.owner_icon, owner:suggestion.owner};
135 138 api.row.add(
136 139 {"active": suggestion.active,
137 140 "owner_data": owner,
138 141 "users_group_id": suggestion.id,
139 142 "group_description": suggestion.description,
140 143 "group_name": suggestion.value}).draw();
141 144 }
142 145 });
143 146 })
144 147
145 148 </script>
146 149
147 150
@@ -1,78 +1,83 b''
1 <%namespace name="base" file="/base/base.mako"/>
2
1 3 <div class="panel panel-default">
2 4 <div class="panel-heading">
3 <h3 class="panel-title">${_('Custom IP Whitelist')}</h3>
5 <h3 class="panel-title">
6 ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')}
7 &nbsp;- ${_('Custom IP Whitelist')}
8 </h3>
4 9 </div>
5 10 <div class="panel-body">
6 11 <div class="ips_wrap">
7 12 <h5>${_('Current IP address')}: <code>${c.rhodecode_user.ip_addr}</code></h5>
8 13 <table class="rctable ip-whitelist">
9 14 <tr>
10 15 <th>${_('IP Address')}</th>
11 16 <th>${_('IP Range')}</th>
12 17 <th>${_('Description')}</th>
13 18 <th></th>
14 19 </tr>
15 20 %if c.default_user_ip_map and c.inherit_default_ips:
16 21 %for ip in c.default_user_ip_map:
17 22 <tr>
18 23 <td class="td-ip"><div class="ip">${ip.ip_addr}</div></td>
19 24 <td class="td-iprange"><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
20 25 <td class="td-description">${h.literal(_('Inherited from %s') % h.link_to('*default*',h.route_path('admin_permissions_ips')))}</td>
21 26 <td></td>
22 27 </tr>
23 28 %endfor
24 29 %endif
25 30
26 31 %if c.user_ip_map:
27 32 %for ip in c.user_ip_map:
28 33 <tr>
29 34 <td class="td-ip"><div class="ip">${ip.ip_addr}</div></td>
30 35 <td class="td-iprange"><div class="ip">${h.ip_range(ip.ip_addr)}</div></td>
31 36 <td class="td-description"><div class="ip">${ip.description}</div></td>
32 37 <td class="td-action">
33 38 ${h.secure_form(h.route_path('edit_user_ips_delete', user_id=c.user.user_id), request=request)}
34 39 ${h.hidden('del_ip_id', ip.ip_id)}
35 40 ${h.submit('remove_', _('Delete'),id="remove_ip_%s" % ip.ip_id,
36 41 class_="btn btn-link btn-danger", onclick="return confirm('"+_('Confirm to delete this ip: %s') % ip.ip_addr+"');")}
37 42 ${h.end_form()}
38 43 </td>
39 44 </tr>
40 45 %endfor
41 46 %endif
42 47 %if not c.default_user_ip_map and not c.user_ip_map:
43 48 <tr>
44 49 <td><h2 class="ip">${_('All IP addresses are allowed')}</h2></td>
45 50 <td></td>
46 51 <td></td>
47 52 <td></td>
48 53 </tr>
49 54 %endif
50 55 </table>
51 56 </div>
52 57
53 58 <div>
54 59 ${h.secure_form(h.route_path('edit_user_ips_add', user_id=c.user.user_id), request=request)}
55 60 <div class="form">
56 61 <!-- fields -->
57 62 <div class="fields">
58 63 <div class="field">
59 64 <div class="label">
60 65 <label for="new_ip">${_('New IP Address')}:</label>
61 66 </div>
62 67 <div class="input">
63 68 ${h.text('new_ip')} ${h.text('description', placeholder=_('Description...'))}
64 69 <span class="help-block pre-formatting">${_('Enter comma separated list of ip addresses like 10.0.0.1,10.0.0.2.\n'
65 70 'Use a ip address with a mask 127.0.0.1/24, to create a network match pattern.\n'
66 71 'To specify multiple entries on an address range use 127.0.0.1-127.0.0.10 syntax')}</span>
67 72 </div>
68 73 </div>
69 74 <div class="buttons">
70 75 ${h.submit('save',_('Add'),class_="btn btn-small")}
71 76 ${h.reset('reset',_('Reset'),class_="btn btn-small")}
72 77 </div>
73 78 </div>
74 79 </div>
75 80 ${h.end_form()}
76 81 </div>
77 82 </div>
78 83 </div>
@@ -1,161 +1,164 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 <div class="panel panel-default user-profile">
4 4 <div class="panel-heading">
5 <h3 class="panel-title">${_('User Profile')}</h3>
5 <h3 class="panel-title">
6 ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')}
7 &nbsp;- ${_('User Profile')}
8 </h3>
6 9 </div>
7 10 <div class="panel-body">
8 11 <div class="user-profile-content">
9 12 ${h.secure_form(h.route_path('user_update', user_id=c.user.user_id), class_='form', request=request)}
10 13 <% readonly = None %>
11 14 <% disabled = "" %>
12 15 %if c.extern_type != 'rhodecode':
13 16 <% readonly = "readonly" %>
14 17 <% disabled = " disabled" %>
15 18 <div class="alert-warning" style="margin:0px 0px 20px 0px; padding: 10px">
16 19 <strong>${_('This user was created from external source (%s). Editing some of the settings is limited.' % c.extern_type)}</strong>
17 20 </div>
18 21 %endif
19 22 <div class="form">
20 23 <div class="fields">
21 24 <div class="field">
22 25 <div class="label photo">
23 26 ${_('Photo')}:
24 27 </div>
25 28 <div class="input profile">
26 29 %if c.visual.use_gravatar:
27 30 ${base.gravatar(c.user.email, 100)}
28 31 <p class="help-block">${_('Change the avatar at')} <a href="http://gravatar.com">gravatar.com</a>.</p>
29 32 %else:
30 33 ${base.gravatar(c.user.email, 100)}
31 34 %endif
32 35 </div>
33 36 </div>
34 37 <div class="field">
35 38 <div class="label">
36 39 ${_('Username')}:
37 40 </div>
38 41 <div class="input">
39 42 ${h.text('username', class_='%s medium' % disabled, readonly=readonly)}
40 43 </div>
41 44 </div>
42 45 <div class="field">
43 46 <div class="label">
44 47 <label for="name">${_('First Name')}:</label>
45 48 </div>
46 49 <div class="input">
47 50 ${h.text('firstname', class_="medium")}
48 51 </div>
49 52 </div>
50 53
51 54 <div class="field">
52 55 <div class="label">
53 56 <label for="lastname">${_('Last Name')}:</label>
54 57 </div>
55 58 <div class="input">
56 59 ${h.text('lastname', class_="medium")}
57 60 </div>
58 61 </div>
59 62
60 63 <div class="field">
61 64 <div class="label">
62 65 <label for="email">${_('Email')}:</label>
63 66 </div>
64 67 <div class="input">
65 68 ## we should be able to edit email !
66 69 ${h.text('email', class_="medium")}
67 70 </div>
68 71 </div>
69 72 <div class="field">
70 73 <div class="label">
71 74 <label for="description">${_('Description')}:</label>
72 75 </div>
73 76 <div class="input textarea editor">
74 77 ${h.textarea('description', rows=10, class_="medium")}
75 78 <% metatags_url = h.literal('''<a href="#metatagsShow" onclick="$('#meta-tags-desc').toggle();return false">meta-tags</a>''') %>
76 79 <span class="help-block">${_('Plain text format with support of {metatags}.').format(metatags=metatags_url)|n}</span>
77 80 <span id="meta-tags-desc" style="display: none">
78 81 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
79 82 ${dt.metatags_help()}
80 83 </span>
81 84 </div>
82 85 </div>
83 86 <div class="field">
84 87 <div class="label">
85 88 ${_('New Password')}:
86 89 </div>
87 90 <div class="input">
88 91 ${h.password('new_password',class_='%s medium' % disabled,autocomplete="off",readonly=readonly)}
89 92 </div>
90 93 </div>
91 94 <div class="field">
92 95 <div class="label">
93 96 ${_('New Password Confirmation')}:
94 97 </div>
95 98 <div class="input">
96 99 ${h.password('password_confirmation',class_="%s medium" % disabled,autocomplete="off",readonly=readonly)}
97 100 </div>
98 101 </div>
99 102 <div class="field">
100 103 <div class="label-text">
101 104 ${_('Active')}:
102 105 </div>
103 106 <div class="input user-checkbox">
104 107 ${h.checkbox('active',value=True)}
105 108 </div>
106 109 </div>
107 110 <div class="field">
108 111 <div class="label-text">
109 112 ${_('Super-admin')}:
110 113 </div>
111 114 <div class="input user-checkbox">
112 115 ${h.checkbox('admin',value=True)}
113 116 </div>
114 117 </div>
115 118 <div class="field">
116 119 <div class="label-text">
117 120 ${_('Authentication type')}:
118 121 </div>
119 122 <div class="input">
120 123 ${h.select('extern_type', c.extern_type, c.allowed_extern_types)}
121 124 <p class="help-block">${_('When user was created using an external source. He is bound to authentication using this method.')}</p>
122 125 </div>
123 126 </div>
124 127 <div class="field">
125 128 <div class="label-text">
126 129 ${_('Name in Source of Record')}:
127 130 </div>
128 131 <div class="input">
129 132 <p>${c.extern_name}</p>
130 133 ${h.hidden('extern_name', readonly="readonly")}
131 134 </div>
132 135 </div>
133 136 <div class="field">
134 137 <div class="label">
135 138 ${_('Language')}:
136 139 </div>
137 140 <div class="input">
138 141 ## allowed_languages is defined in the users.py
139 142 ## c.language comes from base.py as a default language
140 143 ${h.select('language', c.language, c.allowed_languages)}
141 144 <p class="help-block">${h.literal(_('User interface language. Help translate %(rc_link)s into your language.') % {'rc_link': h.link_to('RhodeCode Enterprise', h.route_url('rhodecode_translations'))})}</p>
142 145 </div>
143 146 </div>
144 147 <div class="buttons">
145 148 ${h.submit('save', _('Save'), class_="btn")}
146 149 ${h.reset('reset', _('Reset'), class_="btn")}
147 150 </div>
148 151 </div>
149 152 </div>
150 153 ${h.end_form()}
151 154 </div>
152 155 </div>
153 156 </div>
154 157
155 158 <script>
156 159 $('#language').select2({
157 160 'containerCssClass': "drop-menu",
158 161 'dropdownCssClass': "drop-menu-dropdown",
159 162 'dropdownAutoWidth': true
160 163 });
161 164 </script>
@@ -1,85 +1,90 b''
1 <%namespace name="base" file="/base/base.mako"/>
2
1 3 <div class="panel panel-default">
2 4 <div class="panel-heading">
3 <h3 class="panel-title">${_('SSH Keys')}</h3>
5 <h3 class="panel-title">
6 ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')}
7 &nbsp;- ${_('SSH Keys')}
8 </h3>
4 9 </div>
5 10 <div class="panel-body">
6 11 <div class="sshkeys_wrap">
7 12 <table class="rctable ssh_keys">
8 13 <tr>
9 14 <th>${_('Fingerprint')}</th>
10 15 <th>${_('Description')}</th>
11 16 <th>${_('Created on')}</th>
12 17 <th>${_('Accessed on')}</th>
13 18 <th>${_('Action')}</th>
14 19 </tr>
15 20 %if c.user_ssh_keys:
16 21 %for ssh_key in c.user_ssh_keys:
17 22 <tr class="">
18 23 <td class="">
19 24 <code>${ssh_key.ssh_key_fingerprint}</code>
20 25 </td>
21 26 <td class="td-wrap">${ssh_key.description}</td>
22 27 <td class="td-tags">${h.format_date(ssh_key.created_on)}</td>
23 28 <td class="td-tags">${h.format_date(ssh_key.accessed_on)}</td>
24 29
25 30 <td class="td-action">
26 31 ${h.secure_form(h.route_path('edit_user_ssh_keys_delete', user_id=c.user.user_id), request=request)}
27 32 ${h.hidden('del_ssh_key', ssh_key.ssh_key_id)}
28 33 <button class="btn btn-link btn-danger" type="submit"
29 34 onclick="return confirm('${_('Confirm to remove ssh key %s') % ssh_key.ssh_key_fingerprint}');">
30 35 ${_('Delete')}
31 36 </button>
32 37 ${h.end_form()}
33 38 </td>
34 39 </tr>
35 40 %endfor
36 41 %else:
37 42 <tr><td><div class="ip">${_('No additional ssh keys specified')}</div></td></tr>
38 43 %endif
39 44 </table>
40 45 </div>
41 46
42 47 <div class="user_ssh_keys">
43 48 ${h.secure_form(h.route_path('edit_user_ssh_keys_add', user_id=c.user.user_id), request=request)}
44 49 <div class="form form-vertical">
45 50 <!-- fields -->
46 51 <div class="fields">
47 52 <div class="field">
48 53 <div class="label">
49 54 <label for="new_email">${_('New ssh key')}:</label>
50 55 </div>
51 56 <div class="input">
52 57 ${h.text('description', class_='medium', placeholder=_('Description'))}
53 58 % if c.ssh_key_generator_enabled:
54 59 <a href="${h.route_path('edit_user_ssh_keys_generate_keypair', user_id=c.user.user_id)}">${_('Generate random RSA key')}</a>
55 60 % endif
56 61 </div>
57 62 </div>
58 63
59 64 <div class="field">
60 65 <div class="textarea text-area editor">
61 66 ${h.textarea('key_data',c.default_key, size=30, placeholder=_("Public key, begins with 'ssh-rsa', 'ssh-dss', 'ssh-ed25519', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', or 'ecdsa-sha2-nistp521'"))}
62 67 </div>
63 68 </div>
64 69
65 70 <div class="buttons">
66 71 ${h.submit('save',_('Add'),class_="btn")}
67 72 ${h.reset('reset',_('Reset'),class_="btn")}
68 73 </div>
69 74 % if c.default_key:
70 75 ${_('Click add to use this generate SSH key')}
71 76 % endif
72 77 </div>
73 78 </div>
74 79 ${h.end_form()}
75 80 </div>
76 81 </div>
77 82 </div>
78 83
79 84 <script>
80 85
81 86 $(document).ready(function(){
82 87
83 88
84 89 });
85 90 </script>
@@ -1,58 +1,63 b''
1 <%namespace name="base" file="/base/base.mako"/>
2
1 3 <div class="panel panel-default">
2 4 <div class="panel-heading">
3 <h3 class="panel-title">${_('New SSH Key generation')}</h3>
5 <h3 class="panel-title">
6 ${base.gravatar_with_user(c.user.username, 16, tooltip=False, _class='pull-left')}
7 &nbsp;- ${_('New SSH Key generation')}
8 </h3>
4 9 </div>
5 10 <div class="panel-body">
6 11 %if c.ssh_enabled and c.ssh_key_generator_enabled:
7 12 <p>
8 13 ${_('Below is a 2048 bit generated SSH RSA key.')}<br/>
9 14 ${_('If You wish to use it to access RhodeCode via the SSH please save the private key and click `Use this generated key` at the bottom.')}
10 15 </p>
11 16 <h4>${_('Private key')}</h4>
12 17 <pre>
13 18 # Save the below content as
14 19 # Windows: /Users/{username}/.ssh/id_rsa_rhodecode_access_priv.key
15 20 # macOS: /Users/{yourname}/.ssh/id_rsa_rhodecode_access_priv.key
16 21 # Linux: /home/{username}/.ssh/id_rsa_rhodecode_access_priv.key
17 22
18 23 # Change permissions to 0600 to make it secure, and usable.
19 24 e.g chmod 0600 /home/{username}/.ssh/id_rsa_rhodecode_access_priv.key
20 25 </pre>
21 26
22 27 <div>
23 28 <textarea style="height: 300px">${c.private}</textarea>
24 29 </div>
25 30 <br/>
26 31
27 32 <h4>${_('Public key')}</h4>
28 33 <pre>
29 34 # Save the below content as
30 35 # Windows: /Users/{username}/.ssh/id_rsa_rhodecode_access_pub.key
31 36 # macOS: /Users/{yourname}/.ssh/id_rsa_rhodecode_access_pub.key
32 37 # Linux: /home/{username}/.ssh/id_rsa_rhodecode_access_pub.key
33 38 </pre>
34 39
35 40 <input type="text" value="${c.public}" class="large text" size="100"/>
36 41 <p>
37 42 % if hasattr(c, 'target_form_url'):
38 43 <a href="${c.target_form_url}">${_('Use this generated key')}.</a>
39 44 % else:
40 45 <a href="${h.route_path('edit_user_ssh_keys', user_id=c.user.user_id, _query=dict(default_key=c.public))}">${_('Use this generated key')}.</a>
41 46 % endif
42 47 ${_('Confirmation required on the next screen')}.
43 48 </p>
44 49 % else:
45 50 <h2>
46 51 ${_('SSH key generator has been disabled.')}
47 52 </h2>
48 53 % endif
49 54 </div>
50 55 </div>
51 56
52 57 <script>
53 58
54 59 $(document).ready(function(){
55 60
56 61
57 62 });
58 63 </script>
@@ -1,1136 +1,1136 b''
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 <%!
4 4 ## base64 filter e.g ${ example | base64 }
5 5 def base64(text):
6 6 import base64
7 7 from rhodecode.lib.helpers import safe_str
8 8 return base64.encodestring(safe_str(text))
9 9 %>
10 10
11 11 <%inherit file="root.mako"/>
12 12
13 13 <%include file="/ejs_templates/templates.html"/>
14 14
15 15 <div class="outerwrapper">
16 16 <!-- HEADER -->
17 17 <div class="header">
18 18 <div id="header-inner" class="wrapper">
19 19 <div id="logo">
20 20 <div class="logo-wrapper">
21 21 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
22 22 </div>
23 23 % if c.rhodecode_name:
24 24 <div class="branding">
25 25 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
26 26 </div>
27 27 % endif
28 28 </div>
29 29 <!-- MENU BAR NAV -->
30 30 ${self.menu_bar_nav()}
31 31 <!-- END MENU BAR NAV -->
32 32 </div>
33 33 </div>
34 34 ${self.menu_bar_subnav()}
35 35 <!-- END HEADER -->
36 36
37 37 <!-- CONTENT -->
38 38 <div id="content" class="wrapper">
39 39
40 40 <rhodecode-toast id="notifications"></rhodecode-toast>
41 41
42 42 <div class="main">
43 43 ${next.main()}
44 44 </div>
45 45 </div>
46 46 <!-- END CONTENT -->
47 47
48 48 </div>
49 49 <!-- FOOTER -->
50 50 <div id="footer">
51 51 <div id="footer-inner" class="title wrapper">
52 52 <div>
53 53 <p class="footer-link-right">
54 54 % if c.visual.show_version:
55 55 RhodeCode Enterprise ${c.rhodecode_version} ${c.rhodecode_edition}
56 56 % endif
57 57 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
58 58 % if c.visual.rhodecode_support_url:
59 59 <a href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a>
60 60 % endif
61 61 </p>
62 62 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
63 63 <p class="server-instance" style="display:${sid}">
64 64 ## display hidden instance ID if specially defined
65 65 % if c.rhodecode_instanceid:
66 66 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
67 67 % endif
68 68 </p>
69 69 </div>
70 70 </div>
71 71 </div>
72 72
73 73 <!-- END FOOTER -->
74 74
75 75 ### MAKO DEFS ###
76 76
77 77 <%def name="menu_bar_subnav()">
78 78 </%def>
79 79
80 80 <%def name="breadcrumbs(class_='breadcrumbs')">
81 81 <div class="${class_}">
82 82 ${self.breadcrumbs_links()}
83 83 </div>
84 84 </%def>
85 85
86 86 <%def name="admin_menu(active=None)">
87 87
88 88 <div id="context-bar">
89 89 <div class="wrapper">
90 90 <div class="title">
91 91 <div class="title-content">
92 92 <div class="title-main">
93 93 % if c.is_super_admin:
94 94 ${_('Super-admin Panel')}
95 95 % else:
96 96 ${_('Delegated Admin Panel')}
97 97 % endif
98 98 </div>
99 99 </div>
100 100 </div>
101 101
102 102 <ul id="context-pages" class="navigation horizontal-list">
103 103
104 104 ## super-admin case
105 105 % if c.is_super_admin:
106 106 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
107 107 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
108 108 <li class="${h.is_active('repository_groups', active)}"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
109 109 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
110 110 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
111 111 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
112 112 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
113 113 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
114 114 <li class="${h.is_active('defaults', active)}"><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
115 115 <li class="${h.is_active('settings', active)}"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
116 116
117 117 ## delegated admin
118 118 % elif c.is_delegated_admin:
119 119 <%
120 120 repositories=c.auth_user.repositories_admin or c.can_create_repo
121 121 repository_groups=c.auth_user.repository_groups_admin or c.can_create_repo_group
122 122 user_groups=c.auth_user.user_groups_admin or c.can_create_user_group
123 123 %>
124 124
125 125 %if repositories:
126 126 <li class="${h.is_active('repositories', active)} local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
127 127 %endif
128 128 %if repository_groups:
129 129 <li class="${h.is_active('repository_groups', active)} local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
130 130 %endif
131 131 %if user_groups:
132 132 <li class="${h.is_active('user_groups', active)} local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
133 133 %endif
134 134 % endif
135 135 </ul>
136 136
137 137 </div>
138 138 <div class="clear"></div>
139 139 </div>
140 140 </%def>
141 141
142 142 <%def name="dt_info_panel(elements)">
143 143 <dl class="dl-horizontal">
144 144 %for dt, dd, title, show_items in elements:
145 145 <dt>${dt}:</dt>
146 146 <dd title="${h.tooltip(title)}">
147 147 %if callable(dd):
148 148 ## allow lazy evaluation of elements
149 149 ${dd()}
150 150 %else:
151 151 ${dd}
152 152 %endif
153 153 %if show_items:
154 154 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
155 155 %endif
156 156 </dd>
157 157
158 158 %if show_items:
159 159 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
160 160 %for item in show_items:
161 161 <dt></dt>
162 162 <dd>${item}</dd>
163 163 %endfor
164 164 </div>
165 165 %endif
166 166
167 167 %endfor
168 168 </dl>
169 169 </%def>
170 170
171 171 <%def name="tr_info_entry(element)">
172 172 <% key, val, title, show_items = element %>
173 173
174 174 <tr>
175 175 <td style="vertical-align: top">${key}</td>
176 176 <td title="${h.tooltip(title)}">
177 177 %if callable(val):
178 178 ## allow lazy evaluation of elements
179 179 ${val()}
180 180 %else:
181 181 ${val}
182 182 %endif
183 183 %if show_items:
184 184 <div class="collapsable-content" data-toggle="item-${h.md5_safe(val)[:6]}-details" style="display: none">
185 185 % for item in show_items:
186 186 <dt></dt>
187 187 <dd>${item}</dd>
188 188 % endfor
189 189 </div>
190 190 %endif
191 191 </td>
192 192 <td style="vertical-align: top">
193 193 %if show_items:
194 194 <span class="btn-collapse" data-toggle="item-${h.md5_safe(val)[:6]}-details">${_('Show More')} </span>
195 195 %endif
196 196 </td>
197 197 </tr>
198 198
199 199 </%def>
200 200
201 201 <%def name="gravatar(email, size=16, tooltip=False, tooltip_alt=None, user=None, extra_class=None)">
202 202 <%
203 203 if size > 16:
204 204 gravatar_class = ['gravatar','gravatar-large']
205 205 else:
206 206 gravatar_class = ['gravatar']
207 207
208 208 data_hovercard_url = ''
209 209 data_hovercard_alt = tooltip_alt.replace('<', '&lt;').replace('>', '&gt;') if tooltip_alt else ''
210 210
211 211 if tooltip:
212 212 gravatar_class += ['tooltip-hovercard']
213 213 if extra_class:
214 214 gravatar_class += extra_class
215 215 if tooltip and user:
216 216 if user.username == h.DEFAULT_USER:
217 217 gravatar_class.pop(-1)
218 218 else:
219 219 data_hovercard_url = request.route_path('hovercard_user', user_id=getattr(user, 'user_id', ''))
220 220 gravatar_class = ' '.join(gravatar_class)
221 221
222 222 %>
223 223 <%doc>
224 224 TODO: johbo: For now we serve double size images to make it smooth
225 225 for retina. This is how it worked until now. Should be replaced
226 226 with a better solution at some point.
227 227 </%doc>
228 228
229 229 <img class="${gravatar_class}" height="${size}" width="${size}" data-hovercard-url="${data_hovercard_url}" data-hovercard-alt="${data_hovercard_alt}" src="${h.gravatar_url(email, size * 2)}" />
230 230 </%def>
231 231
232 232
233 <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False)">
233 <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False, _class='rc-user')">
234 234 <%
235 235 email = h.email_or_none(contact)
236 236 rc_user = h.discover_user(contact)
237 237 %>
238 238
239 <div class="rc-user">
239 <div class="${_class}">
240 240 ${self.gravatar(email, size, tooltip=tooltip, tooltip_alt=contact, user=rc_user)}
241 241 <span class="${('user user-disabled' if show_disabled else 'user')}"> ${h.link_to_user(rc_user or contact)}</span>
242 242 </div>
243 243 </%def>
244 244
245 245
246 246 <%def name="user_group_icon(user_group=None, size=16, tooltip=False)">
247 247 <%
248 248 if (size > 16):
249 249 gravatar_class = 'icon-user-group-alt'
250 250 else:
251 251 gravatar_class = 'icon-user-group-alt'
252 252
253 253 if tooltip:
254 254 gravatar_class += ' tooltip-hovercard'
255 255
256 256 data_hovercard_url = request.route_path('hovercard_user_group', user_group_id=user_group.users_group_id)
257 257 %>
258 258 <%doc>
259 259 TODO: johbo: For now we serve double size images to make it smooth
260 260 for retina. This is how it worked until now. Should be replaced
261 261 with a better solution at some point.
262 262 </%doc>
263 263
264 264 <i style="font-size: ${size}px" class="${gravatar_class} x-icon-size-${size}" data-hovercard-url="${data_hovercard_url}"></i>
265 265 </%def>
266 266
267 267 <%def name="repo_page_title(repo_instance)">
268 268 <div class="title-content repo-title">
269 269
270 270 <div class="title-main">
271 271 ## SVN/HG/GIT icons
272 272 %if h.is_hg(repo_instance):
273 273 <i class="icon-hg"></i>
274 274 %endif
275 275 %if h.is_git(repo_instance):
276 276 <i class="icon-git"></i>
277 277 %endif
278 278 %if h.is_svn(repo_instance):
279 279 <i class="icon-svn"></i>
280 280 %endif
281 281
282 282 ## public/private
283 283 %if repo_instance.private:
284 284 <i class="icon-repo-private"></i>
285 285 %else:
286 286 <i class="icon-repo-public"></i>
287 287 %endif
288 288
289 289 ## repo name with group name
290 290 ${h.breadcrumb_repo_link(repo_instance)}
291 291
292 292 ## Context Actions
293 293 <div class="pull-right">
294 294 %if c.rhodecode_user.username != h.DEFAULT_USER:
295 295 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid, _query=dict(auth_token=c.rhodecode_user.feed_token))}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
296 296
297 297 <a href="#WatchRepo" onclick="toggleFollowingRepo(this, templateContext.repo_id); return false" title="${_('Watch this Repository and actions on it in your personalized journal')}" class="btn btn-sm ${('watching' if c.repository_is_user_following else '')}">
298 298 % if c.repository_is_user_following:
299 299 <i class="icon-eye-off"></i>${_('Unwatch')}
300 300 % else:
301 301 <i class="icon-eye"></i>${_('Watch')}
302 302 % endif
303 303
304 304 </a>
305 305 %else:
306 306 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid)}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
307 307 %endif
308 308 </div>
309 309
310 310 </div>
311 311
312 312 ## FORKED
313 313 %if repo_instance.fork:
314 314 <p class="discreet">
315 315 <i class="icon-code-fork"></i> ${_('Fork of')}
316 316 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
317 317 </p>
318 318 %endif
319 319
320 320 ## IMPORTED FROM REMOTE
321 321 %if repo_instance.clone_uri:
322 322 <p class="discreet">
323 323 <i class="icon-code-fork"></i> ${_('Clone from')}
324 324 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
325 325 </p>
326 326 %endif
327 327
328 328 ## LOCKING STATUS
329 329 %if repo_instance.locked[0]:
330 330 <p class="locking_locked discreet">
331 331 <i class="icon-repo-lock"></i>
332 332 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
333 333 </p>
334 334 %elif repo_instance.enable_locking:
335 335 <p class="locking_unlocked discreet">
336 336 <i class="icon-repo-unlock"></i>
337 337 ${_('Repository not locked. Pull repository to lock it.')}
338 338 </p>
339 339 %endif
340 340
341 341 </div>
342 342 </%def>
343 343
344 344 <%def name="repo_menu(active=None)">
345 345 <%
346 346 ## determine if we have "any" option available
347 347 can_lock = h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking
348 348 has_actions = can_lock
349 349
350 350 %>
351 351 % if c.rhodecode_db_repo.archived:
352 352 <div class="alert alert-warning text-center">
353 353 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
354 354 </div>
355 355 % endif
356 356
357 357 <!--- REPO CONTEXT BAR -->
358 358 <div id="context-bar">
359 359 <div class="wrapper">
360 360
361 361 <div class="title">
362 362 ${self.repo_page_title(c.rhodecode_db_repo)}
363 363 </div>
364 364
365 365 <ul id="context-pages" class="navigation horizontal-list">
366 366 <li class="${h.is_active('summary', active)}"><a class="menulink" href="${h.route_path('repo_summary', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
367 367 <li class="${h.is_active('commits', active)}"><a class="menulink" href="${h.route_path('repo_commits', repo_name=c.repo_name)}"><div class="menulabel">${_('Commits')}</div></a></li>
368 368 <li class="${h.is_active('files', active)}"><a class="menulink" href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.rhodecode_db_repo.landing_rev[1], f_path='')}"><div class="menulabel">${_('Files')}</div></a></li>
369 369 <li class="${h.is_active('compare', active)}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
370 370
371 371 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
372 372 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
373 373 <li class="${h.is_active('showpullrequest', active)}">
374 374 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
375 375 <div class="menulabel">
376 376 ${_('Pull Requests')} <span class="menulink-counter">${c.repository_pull_requests}</span>
377 377 </div>
378 378 </a>
379 379 </li>
380 380 %endif
381 381
382 382 <li class="${h.is_active('artifacts', active)}">
383 383 <a class="menulink" href="${h.route_path('repo_artifacts_list',repo_name=c.repo_name)}">
384 384 <div class="menulabel">
385 385 ${_('Artifacts')} <span class="menulink-counter">${c.repository_artifacts}</span>
386 386 </div>
387 387 </a>
388 388 </li>
389 389
390 390 %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
391 391 <li class="${h.is_active('settings', active)}"><a class="menulink" href="${h.route_path('edit_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Repository Settings')}</div></a></li>
392 392 %endif
393 393
394 394 <li class="${h.is_active('options', active)}">
395 395 % if has_actions:
396 396 <a class="menulink dropdown">
397 397 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
398 398 </a>
399 399 <ul class="submenu">
400 400 %if can_lock:
401 401 %if c.rhodecode_db_repo.locked[0]:
402 402 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock Repository')}</a></li>
403 403 %else:
404 404 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock Repository')}</a></li>
405 405 %endif
406 406 %endif
407 407 </ul>
408 408 % endif
409 409 </li>
410 410
411 411 </ul>
412 412 </div>
413 413 <div class="clear"></div>
414 414 </div>
415 415
416 416 <!--- REPO END CONTEXT BAR -->
417 417
418 418 </%def>
419 419
420 420 <%def name="repo_group_page_title(repo_group_instance)">
421 421 <div class="title-content">
422 422 <div class="title-main">
423 423 ## Repository Group icon
424 424 <i class="icon-repo-group"></i>
425 425
426 426 ## repo name with group name
427 427 ${h.breadcrumb_repo_group_link(repo_group_instance)}
428 428 </div>
429 429
430 430 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
431 431 <div class="repo-group-desc discreet">
432 432 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
433 433 </div>
434 434
435 435 </div>
436 436 </%def>
437 437
438 438
439 439 <%def name="repo_group_menu(active=None)">
440 440 <%
441 441 gr_name = c.repo_group.group_name if c.repo_group else None
442 442 # create repositories with write permission on group is set to true
443 443 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
444 444
445 445 %>
446 446
447 447
448 448 <!--- REPO GROUP CONTEXT BAR -->
449 449 <div id="context-bar">
450 450 <div class="wrapper">
451 451 <div class="title">
452 452 ${self.repo_group_page_title(c.repo_group)}
453 453 </div>
454 454
455 455 <ul id="context-pages" class="navigation horizontal-list">
456 456 <li class="${h.is_active('home', active)}">
457 457 <a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a>
458 458 </li>
459 459 % if c.is_super_admin or group_admin:
460 460 <li class="${h.is_active('settings', active)}">
461 461 <a class="menulink" href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}"><div class="menulabel">${_('Group Settings')}</div></a>
462 462 </li>
463 463 % endif
464 464
465 465 </ul>
466 466 </div>
467 467 <div class="clear"></div>
468 468 </div>
469 469
470 470 <!--- REPO GROUP CONTEXT BAR -->
471 471
472 472 </%def>
473 473
474 474
475 475 <%def name="usermenu(active=False)">
476 476 <%
477 477 not_anonymous = c.rhodecode_user.username != h.DEFAULT_USER
478 478
479 479 gr_name = c.repo_group.group_name if (hasattr(c, 'repo_group') and c.repo_group) else None
480 480 # create repositories with write permission on group is set to true
481 481
482 482 can_fork = c.is_super_admin or h.HasPermissionAny('hg.fork.repository')()
483 483 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
484 484 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
485 485 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
486 486
487 487 can_create_repos = c.is_super_admin or c.can_create_repo
488 488 can_create_repo_groups = c.is_super_admin or c.can_create_repo_group
489 489
490 490 can_create_repos_in_group = c.is_super_admin or group_admin or (group_write and create_on_write)
491 491 can_create_repo_groups_in_group = c.is_super_admin or group_admin
492 492 %>
493 493
494 494 % if not_anonymous:
495 495 <%
496 496 default_target_group = dict()
497 497 if c.rhodecode_user.personal_repo_group:
498 498 default_target_group = dict(parent_group=c.rhodecode_user.personal_repo_group.group_id)
499 499 %>
500 500
501 501 ## create action
502 502 <li>
503 503 <a href="#create-actions" onclick="return false;" class="menulink childs">
504 504 <i class="tooltip icon-plus-circled" title="${_('Create')}"></i>
505 505 </a>
506 506
507 507 <div class="action-menu submenu">
508 508
509 509 <ol>
510 510 ## scope of within a repository
511 511 % if hasattr(c, 'rhodecode_db_repo') and c.rhodecode_db_repo:
512 512 <li class="submenu-title">${_('This Repository')}</li>
513 513 <li>
514 514 <a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a>
515 515 </li>
516 516 % if can_fork:
517 517 <li>
518 518 <a href="${h.route_path('repo_fork_new',repo_name=c.repo_name,_query=default_target_group)}">${_('Fork this repository')}</a>
519 519 </li>
520 520 % endif
521 521 % endif
522 522
523 523 ## scope of within repository groups
524 524 % if hasattr(c, 'repo_group') and c.repo_group and (can_create_repos_in_group or can_create_repo_groups_in_group):
525 525 <li class="submenu-title">${_('This Repository Group')}</li>
526 526
527 527 % if can_create_repos_in_group:
528 528 <li>
529 529 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('New Repository')}</a>
530 530 </li>
531 531 % endif
532 532
533 533 % if can_create_repo_groups_in_group:
534 534 <li>
535 535 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'New Repository Group')}</a>
536 536 </li>
537 537 % endif
538 538 % endif
539 539
540 540 ## personal group
541 541 % if c.rhodecode_user.personal_repo_group:
542 542 <li class="submenu-title">Personal Group</li>
543 543
544 544 <li>
545 545 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}" >${_('New Repository')} </a>
546 546 </li>
547 547
548 548 <li>
549 549 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}">${_('New Repository Group')} </a>
550 550 </li>
551 551 % endif
552 552
553 553 ## Global actions
554 554 <li class="submenu-title">RhodeCode</li>
555 555 % if can_create_repos:
556 556 <li>
557 557 <a href="${h.route_path('repo_new')}" >${_('New Repository')}</a>
558 558 </li>
559 559 % endif
560 560
561 561 % if can_create_repo_groups:
562 562 <li>
563 563 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
564 564 </li>
565 565 % endif
566 566
567 567 <li>
568 568 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
569 569 </li>
570 570
571 571 </ol>
572 572
573 573 </div>
574 574 </li>
575 575
576 576 ## notifications
577 577 <li>
578 578 <a class="${('empty' if c.unread_notifications == 0 else '')}" href="${h.route_path('notifications_show_all')}">
579 579 ${c.unread_notifications}
580 580 </a>
581 581 </li>
582 582 % endif
583 583
584 584 ## USER MENU
585 585 <li id="quick_login_li" class="${'active' if active else ''}">
586 586 % if c.rhodecode_user.username == h.DEFAULT_USER:
587 587 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
588 588 ${gravatar(c.rhodecode_user.email, 20)}
589 589 <span class="user">
590 590 <span>${_('Sign in')}</span>
591 591 </span>
592 592 </a>
593 593 % else:
594 594 ## logged in user
595 595 <a id="quick_login_link" class="menulink childs">
596 596 ${gravatar(c.rhodecode_user.email, 20)}
597 597 <span class="user">
598 598 <span class="menu_link_user">${c.rhodecode_user.username}</span>
599 599 <div class="show_more"></div>
600 600 </span>
601 601 </a>
602 602 ## subnav with menu for logged in user
603 603 <div class="user-menu submenu">
604 604 <div id="quick_login">
605 605 %if c.rhodecode_user.username != h.DEFAULT_USER:
606 606 <div class="">
607 607 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
608 608 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
609 609 <div class="email">${c.rhodecode_user.email}</div>
610 610 </div>
611 611 <div class="">
612 612 <ol class="links">
613 613 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
614 614 % if c.rhodecode_user.personal_repo_group:
615 615 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
616 616 % endif
617 617 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
618 618
619 619 % if c.debug_style:
620 620 <li>
621 621 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
622 622 <div class="menulabel">${_('[Style]')}</div>
623 623 </a>
624 624 </li>
625 625 % endif
626 626
627 627 ## bookmark-items
628 628 <li class="bookmark-items">
629 629 ${_('Bookmarks')}
630 630 <div class="pull-right">
631 631 <a href="${h.route_path('my_account_bookmarks')}">
632 632
633 633 <i class="icon-cog"></i>
634 634 </a>
635 635 </div>
636 636 </li>
637 637 % if not c.bookmark_items:
638 638 <li>
639 639 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
640 640 </li>
641 641 % endif
642 642 % for item in c.bookmark_items:
643 643 <li>
644 644 % if item.repository:
645 645 <div>
646 646 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
647 647 <code>${item.position}</code>
648 648 % if item.repository.repo_type == 'hg':
649 649 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
650 650 % elif item.repository.repo_type == 'git':
651 651 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
652 652 % elif item.repository.repo_type == 'svn':
653 653 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
654 654 % endif
655 655 ${(item.title or h.shorter(item.repository.repo_name, 30))}
656 656 </a>
657 657 </div>
658 658 % elif item.repository_group:
659 659 <div>
660 660 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
661 661 <code>${item.position}</code>
662 662 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
663 663 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
664 664 </a>
665 665 </div>
666 666 % else:
667 667 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
668 668 <code>${item.position}</code>
669 669 ${item.title}
670 670 </a>
671 671 % endif
672 672 </li>
673 673 % endfor
674 674
675 675 <li class="logout">
676 676 ${h.secure_form(h.route_path('logout'), request=request)}
677 677 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
678 678 ${h.end_form()}
679 679 </li>
680 680 </ol>
681 681 </div>
682 682 %endif
683 683 </div>
684 684 </div>
685 685
686 686 % endif
687 687 </li>
688 688 </%def>
689 689
690 690 <%def name="menu_items(active=None)">
691 691
692 692 <ul id="quick" class="main_nav navigation horizontal-list">
693 693 ## notice box for important system messages
694 694 <li style="display: none">
695 695 <a class="notice-box" href="#openNotice" onclick="return false">
696 696 <div class="menulabel-notice" >
697 697 0
698 698 </div>
699 699 </a>
700 700 </li>
701 701
702 702 ## Main filter
703 703 <li>
704 704 <div class="menulabel main_filter_box">
705 705 <div class="main_filter_input_box">
706 706 <ul class="searchItems">
707 707
708 708 <li class="searchTag searchTagIcon">
709 709 <i class="icon-search"></i>
710 710 </li>
711 711
712 712 % if c.template_context['search_context']['repo_id']:
713 713 <li class="searchTag searchTagFilter searchTagHidable" >
714 714 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
715 715 <span class="tag">
716 716 This repo
717 717 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
718 718 </span>
719 719 ##</a>
720 720 </li>
721 721 % elif c.template_context['search_context']['repo_group_id']:
722 722 <li class="searchTag searchTagFilter searchTagHidable">
723 723 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
724 724 <span class="tag">
725 725 This group
726 726 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
727 727 </span>
728 728 ##</a>
729 729 </li>
730 730 % endif
731 731
732 732 <li class="searchTagInput">
733 733 <input class="main_filter_input" id="main_filter" size="25" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
734 734 </li>
735 735 <li class="searchTag searchTagHelp">
736 736 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
737 737 </li>
738 738 </ul>
739 739 </div>
740 740 </div>
741 741
742 742 <div id="main_filter_help" style="display: none">
743 743 - Use '/' key to quickly access this field.
744 744
745 745 - Enter a name of repository, or repository group for quick search.
746 746
747 747 - Prefix query to allow special search:
748 748
749 749 user:admin, to search for usernames, always global
750 750
751 751 user_group:devops, to search for user groups, always global
752 752
753 753 commit:efced4, to search for commits, scoped to repositories or groups
754 754
755 755 file:models.py, to search for file paths, scoped to repositories or groups
756 756
757 757 % if c.template_context['search_context']['repo_id']:
758 758 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
759 759 % elif c.template_context['search_context']['repo_group_id']:
760 760 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
761 761 % else:
762 762 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
763 763 % endif
764 764 </div>
765 765 </li>
766 766
767 767 ## ROOT MENU
768 768 <li class="${h.is_active('home', active)}">
769 769 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
770 770 <div class="menulabel">${_('Home')}</div>
771 771 </a>
772 772 </li>
773 773
774 774 %if c.rhodecode_user.username != h.DEFAULT_USER:
775 775 <li class="${h.is_active('journal', active)}">
776 776 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
777 777 <div class="menulabel">${_('Journal')}</div>
778 778 </a>
779 779 </li>
780 780 %else:
781 781 <li class="${h.is_active('journal', active)}">
782 782 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
783 783 <div class="menulabel">${_('Public journal')}</div>
784 784 </a>
785 785 </li>
786 786 %endif
787 787
788 788 <li class="${h.is_active('gists', active)}">
789 789 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
790 790 <div class="menulabel">${_('Gists')}</div>
791 791 </a>
792 792 </li>
793 793
794 794 % if c.is_super_admin or c.is_delegated_admin:
795 795 <li class="${h.is_active('admin', active)}">
796 796 <a class="menulink childs" title="${_('Admin settings')}" href="${h.route_path('admin_home')}">
797 797 <div class="menulabel">${_('Admin')} </div>
798 798 </a>
799 799 </li>
800 800 % endif
801 801
802 802 ## render extra user menu
803 803 ${usermenu(active=(active=='my_account'))}
804 804
805 805 </ul>
806 806
807 807 <script type="text/javascript">
808 808 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
809 809
810 810 var formatRepoResult = function(result, container, query, escapeMarkup) {
811 811 return function(data, escapeMarkup) {
812 812 if (!data.repo_id){
813 813 return data.text; // optgroup text Repositories
814 814 }
815 815
816 816 var tmpl = '';
817 817 var repoType = data['repo_type'];
818 818 var repoName = data['text'];
819 819
820 820 if(data && data.type == 'repo'){
821 821 if(repoType === 'hg'){
822 822 tmpl += '<i class="icon-hg"></i> ';
823 823 }
824 824 else if(repoType === 'git'){
825 825 tmpl += '<i class="icon-git"></i> ';
826 826 }
827 827 else if(repoType === 'svn'){
828 828 tmpl += '<i class="icon-svn"></i> ';
829 829 }
830 830 if(data['private']){
831 831 tmpl += '<i class="icon-lock" ></i> ';
832 832 }
833 833 else if(visualShowPublicIcon){
834 834 tmpl += '<i class="icon-unlock-alt"></i> ';
835 835 }
836 836 }
837 837 tmpl += escapeMarkup(repoName);
838 838 return tmpl;
839 839
840 840 }(result, escapeMarkup);
841 841 };
842 842
843 843 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
844 844 return function(data, escapeMarkup) {
845 845 if (!data.repo_group_id){
846 846 return data.text; // optgroup text Repositories
847 847 }
848 848
849 849 var tmpl = '';
850 850 var repoGroupName = data['text'];
851 851
852 852 if(data){
853 853
854 854 tmpl += '<i class="icon-repo-group"></i> ';
855 855
856 856 }
857 857 tmpl += escapeMarkup(repoGroupName);
858 858 return tmpl;
859 859
860 860 }(result, escapeMarkup);
861 861 };
862 862
863 863 var escapeRegExChars = function (value) {
864 864 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
865 865 };
866 866
867 867 var getRepoIcon = function(repo_type) {
868 868 if (repo_type === 'hg') {
869 869 return '<i class="icon-hg"></i> ';
870 870 }
871 871 else if (repo_type === 'git') {
872 872 return '<i class="icon-git"></i> ';
873 873 }
874 874 else if (repo_type === 'svn') {
875 875 return '<i class="icon-svn"></i> ';
876 876 }
877 877 return ''
878 878 };
879 879
880 880 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
881 881
882 882 if (value.split(':').length === 2) {
883 883 value = value.split(':')[1]
884 884 }
885 885
886 886 var searchType = data['type'];
887 887 var searchSubType = data['subtype'];
888 888 var valueDisplay = data['value_display'];
889 889 var valueIcon = data['value_icon'];
890 890
891 891 var pattern = '(' + escapeRegExChars(value) + ')';
892 892
893 893 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
894 894
895 895 // highlight match
896 896 if (searchType != 'text') {
897 897 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
898 898 }
899 899
900 900 var icon = '';
901 901
902 902 if (searchType === 'hint') {
903 903 icon += '<i class="icon-repo-group"></i> ';
904 904 }
905 905 // full text search/hints
906 906 else if (searchType === 'search') {
907 907 if (valueIcon === undefined) {
908 908 icon += '<i class="icon-more"></i> ';
909 909 } else {
910 910 icon += valueIcon + ' ';
911 911 }
912 912
913 913 if (searchSubType !== undefined && searchSubType == 'repo') {
914 914 valueDisplay += '<div class="pull-right tag">repository</div>';
915 915 }
916 916 else if (searchSubType !== undefined && searchSubType == 'repo_group') {
917 917 valueDisplay += '<div class="pull-right tag">repo group</div>';
918 918 }
919 919 }
920 920 // repository
921 921 else if (searchType === 'repo') {
922 922
923 923 var repoIcon = getRepoIcon(data['repo_type']);
924 924 icon += repoIcon;
925 925
926 926 if (data['private']) {
927 927 icon += '<i class="icon-lock" ></i> ';
928 928 }
929 929 else if (visualShowPublicIcon) {
930 930 icon += '<i class="icon-unlock-alt"></i> ';
931 931 }
932 932 }
933 933 // repository groups
934 934 else if (searchType === 'repo_group') {
935 935 icon += '<i class="icon-repo-group"></i> ';
936 936 }
937 937 // user group
938 938 else if (searchType === 'user_group') {
939 939 icon += '<i class="icon-group"></i> ';
940 940 }
941 941 // user
942 942 else if (searchType === 'user') {
943 943 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
944 944 }
945 945 // commit
946 946 else if (searchType === 'commit') {
947 947 var repo_data = data['repo_data'];
948 948 var repoIcon = getRepoIcon(repo_data['repository_type']);
949 949 if (repoIcon) {
950 950 icon += repoIcon;
951 951 } else {
952 952 icon += '<i class="icon-tag"></i>';
953 953 }
954 954 }
955 955 // file
956 956 else if (searchType === 'file') {
957 957 var repo_data = data['repo_data'];
958 958 var repoIcon = getRepoIcon(repo_data['repository_type']);
959 959 if (repoIcon) {
960 960 icon += repoIcon;
961 961 } else {
962 962 icon += '<i class="icon-tag"></i>';
963 963 }
964 964 }
965 965 // generic text
966 966 else if (searchType === 'text') {
967 967 icon = '';
968 968 }
969 969
970 970 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
971 971 return tmpl.format(icon, valueDisplay);
972 972 };
973 973
974 974 var handleSelect = function(element, suggestion) {
975 975 if (suggestion.type === "hint") {
976 976 // we skip action
977 977 $('#main_filter').focus();
978 978 }
979 979 else if (suggestion.type === "text") {
980 980 // we skip action
981 981 $('#main_filter').focus();
982 982
983 983 } else {
984 984 window.location = suggestion['url'];
985 985 }
986 986 };
987 987
988 988 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
989 989 if (queryLowerCase.split(':').length === 2) {
990 990 queryLowerCase = queryLowerCase.split(':')[1]
991 991 }
992 992 if (suggestion.type === "text") {
993 993 // special case we don't want to "skip" display for
994 994 return true
995 995 }
996 996 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
997 997 };
998 998
999 999 var cleanContext = {
1000 1000 repo_view_type: null,
1001 1001
1002 1002 repo_id: null,
1003 1003 repo_name: "",
1004 1004
1005 1005 repo_group_id: null,
1006 1006 repo_group_name: null
1007 1007 };
1008 1008 var removeGoToFilter = function () {
1009 1009 $('.searchTagHidable').hide();
1010 1010 $('#main_filter').autocomplete(
1011 1011 'setOptions', {params:{search_context: cleanContext}});
1012 1012 };
1013 1013
1014 1014 $('#main_filter').autocomplete({
1015 1015 serviceUrl: pyroutes.url('goto_switcher_data'),
1016 1016 params: {
1017 1017 "search_context": templateContext.search_context
1018 1018 },
1019 1019 minChars:2,
1020 1020 maxHeight:400,
1021 1021 deferRequestBy: 300, //miliseconds
1022 1022 tabDisabled: true,
1023 1023 autoSelectFirst: false,
1024 1024 containerClass: 'autocomplete-qfilter-suggestions',
1025 1025 formatResult: autocompleteMainFilterFormatResult,
1026 1026 lookupFilter: autocompleteMainFilterResult,
1027 1027 onSelect: function (element, suggestion) {
1028 1028 handleSelect(element, suggestion);
1029 1029 return false;
1030 1030 },
1031 1031 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
1032 1032 if (jqXHR !== 'abort') {
1033 1033 alert("Error during search.\nError code: {0}".format(textStatus));
1034 1034 window.location = '';
1035 1035 }
1036 1036 },
1037 1037 onSearchStart: function (params) {
1038 1038 $('.searchTag.searchTagIcon').html('<i class="icon-spin animate-spin"></i>')
1039 1039 },
1040 1040 onSearchComplete: function (query, suggestions) {
1041 1041 $('.searchTag.searchTagIcon').html('<i class="icon-search"></i>')
1042 1042 },
1043 1043 });
1044 1044
1045 1045 showMainFilterBox = function () {
1046 1046 $('#main_filter_help').toggle();
1047 1047 };
1048 1048
1049 1049 $('#main_filter').on('keydown.autocomplete', function (e) {
1050 1050
1051 1051 var BACKSPACE = 8;
1052 1052 var el = $(e.currentTarget);
1053 1053 if(e.which === BACKSPACE){
1054 1054 var inputVal = el.val();
1055 1055 if (inputVal === ""){
1056 1056 removeGoToFilter()
1057 1057 }
1058 1058 }
1059 1059 });
1060 1060
1061 1061 </script>
1062 1062 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
1063 1063 </%def>
1064 1064
1065 1065 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
1066 1066 <div class="modal-dialog">
1067 1067 <div class="modal-content">
1068 1068 <div class="modal-header">
1069 1069 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1070 1070 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
1071 1071 </div>
1072 1072 <div class="modal-body">
1073 1073 <div class="block-left">
1074 1074 <table class="keyboard-mappings">
1075 1075 <tbody>
1076 1076 <tr>
1077 1077 <th></th>
1078 1078 <th>${_('Site-wide shortcuts')}</th>
1079 1079 </tr>
1080 1080 <%
1081 1081 elems = [
1082 1082 ('/', 'Use quick search box'),
1083 1083 ('g h', 'Goto home page'),
1084 1084 ('g g', 'Goto my private gists page'),
1085 1085 ('g G', 'Goto my public gists page'),
1086 1086 ('g 0-9', 'Goto bookmarked items from 0-9'),
1087 1087 ('n r', 'New repository page'),
1088 1088 ('n g', 'New gist page'),
1089 1089 ]
1090 1090 %>
1091 1091 %for key, desc in elems:
1092 1092 <tr>
1093 1093 <td class="keys">
1094 1094 <span class="key tag">${key}</span>
1095 1095 </td>
1096 1096 <td>${desc}</td>
1097 1097 </tr>
1098 1098 %endfor
1099 1099 </tbody>
1100 1100 </table>
1101 1101 </div>
1102 1102 <div class="block-left">
1103 1103 <table class="keyboard-mappings">
1104 1104 <tbody>
1105 1105 <tr>
1106 1106 <th></th>
1107 1107 <th>${_('Repositories')}</th>
1108 1108 </tr>
1109 1109 <%
1110 1110 elems = [
1111 1111 ('g s', 'Goto summary page'),
1112 1112 ('g c', 'Goto changelog page'),
1113 1113 ('g f', 'Goto files page'),
1114 1114 ('g F', 'Goto files page with file search activated'),
1115 1115 ('g p', 'Goto pull requests page'),
1116 1116 ('g o', 'Goto repository settings'),
1117 1117 ('g O', 'Goto repository access permissions settings'),
1118 1118 ]
1119 1119 %>
1120 1120 %for key, desc in elems:
1121 1121 <tr>
1122 1122 <td class="keys">
1123 1123 <span class="key tag">${key}</span>
1124 1124 </td>
1125 1125 <td>${desc}</td>
1126 1126 </tr>
1127 1127 %endfor
1128 1128 </tbody>
1129 1129 </table>
1130 1130 </div>
1131 1131 </div>
1132 1132 <div class="modal-footer">
1133 1133 </div>
1134 1134 </div><!-- /.modal-content -->
1135 1135 </div><!-- /.modal-dialog -->
1136 1136 </div><!-- /.modal -->
General Comments 0
You need to be logged in to leave comments. Login now