##// END OF EJS Templates
artifacts: added admin panel to manage all artifacts in an instance.
milka -
r4661:df96df1f default
parent child Browse files
Show More
@@ -1,269 +1,270 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import os
22 22 import time
23 23 import errno
24 24 import hashlib
25 25
26 26 from rhodecode.lib.ext_json import json
27 27 from rhodecode.apps.file_store import utils
28 28 from rhodecode.apps.file_store.extensions import resolve_extensions
29 29 from rhodecode.apps.file_store.exceptions import (
30 30 FileNotAllowedException, FileOverSizeException)
31 31
32 32 METADATA_VER = 'v1'
33 33
34 34
35 35 def safe_make_dirs(dir_path):
36 36 if not os.path.exists(dir_path):
37 37 try:
38 38 os.makedirs(dir_path)
39 39 except OSError as e:
40 40 if e.errno != errno.EEXIST:
41 41 raise
42 42 return
43 43
44 44
45 45 class LocalFileStorage(object):
46 46
47 47 @classmethod
48 48 def apply_counter(cls, counter, filename):
49 49 name_counted = '%d-%s' % (counter, filename)
50 50 return name_counted
51 51
52 52 @classmethod
53 53 def resolve_name(cls, name, directory):
54 54 """
55 55 Resolves a unique name and the correct path. If a filename
56 56 for that path already exists then a numeric prefix with values > 0 will be
57 57 added, for example test.jpg -> 1-test.jpg etc. initially file would have 0 prefix.
58 58
59 59 :param name: base name of file
60 60 :param directory: absolute directory path
61 61 """
62 62
63 63 counter = 0
64 64 while True:
65 65 name_counted = cls.apply_counter(counter, name)
66 66
67 67 # sub_store prefix to optimize disk usage, e.g some_path/ab/final_file
68 68 sub_store = cls._sub_store_from_filename(name_counted)
69 69 sub_store_path = os.path.join(directory, sub_store)
70 70 safe_make_dirs(sub_store_path)
71 71
72 72 path = os.path.join(sub_store_path, name_counted)
73 73 if not os.path.exists(path):
74 74 return name_counted, path
75 75 counter += 1
76 76
77 77 @classmethod
78 78 def _sub_store_from_filename(cls, filename):
79 79 return filename[:2]
80 80
81 81 @classmethod
82 82 def calculate_path_hash(cls, file_path):
83 83 """
84 84 Efficient calculation of file_path sha256 sum
85 85
86 86 :param file_path:
87 87 :return: sha256sum
88 88 """
89 89 digest = hashlib.sha256()
90 90 with open(file_path, 'rb') as f:
91 91 for chunk in iter(lambda: f.read(1024 * 100), b""):
92 92 digest.update(chunk)
93 93
94 94 return digest.hexdigest()
95 95
96 96 def __init__(self, base_path, extension_groups=None):
97 97
98 98 """
99 99 Local file storage
100 100
101 101 :param base_path: the absolute base path where uploads are stored
102 102 :param extension_groups: extensions string
103 103 """
104 104
105 105 extension_groups = extension_groups or ['any']
106 106 self.base_path = base_path
107 107 self.extensions = resolve_extensions([], groups=extension_groups)
108 108
109 109 def __repr__(self):
110 110 return '{}@{}'.format(self.__class__, self.base_path)
111 111
112 112 def store_path(self, filename):
113 113 """
114 114 Returns absolute file path of the filename, joined to the
115 115 base_path.
116 116
117 117 :param filename: base name of file
118 118 """
119 119 prefix_dir = ''
120 120 if '/' in filename:
121 121 prefix_dir, filename = filename.split('/')
122 122 sub_store = self._sub_store_from_filename(filename)
123 123 else:
124 124 sub_store = self._sub_store_from_filename(filename)
125 125 return os.path.join(self.base_path, prefix_dir, sub_store, filename)
126 126
127 127 def delete(self, filename):
128 128 """
129 129 Deletes the filename. Filename is resolved with the
130 130 absolute path based on base_path. If file does not exist,
131 131 returns **False**, otherwise **True**
132 132
133 133 :param filename: base name of file
134 134 """
135 135 if self.exists(filename):
136 136 os.remove(self.store_path(filename))
137 137 return True
138 138 return False
139 139
140 140 def exists(self, filename):
141 141 """
142 142 Checks if file exists. Resolves filename's absolute
143 143 path based on base_path.
144 144
145 145 :param filename: file_uid name of file, e.g 0-f62b2b2d-9708-4079-a071-ec3f958448d4.svg
146 146 """
147 147 return os.path.exists(self.store_path(filename))
148 148
149 149 def filename_allowed(self, filename, extensions=None):
150 150 """Checks if a filename has an allowed extension
151 151
152 152 :param filename: base name of file
153 153 :param extensions: iterable of extensions (or self.extensions)
154 154 """
155 155 _, ext = os.path.splitext(filename)
156 156 return self.extension_allowed(ext, extensions)
157 157
158 158 def extension_allowed(self, ext, extensions=None):
159 159 """
160 160 Checks if an extension is permitted. Both e.g. ".jpg" and
161 161 "jpg" can be passed in. Extension lookup is case-insensitive.
162 162
163 163 :param ext: extension to check
164 164 :param extensions: iterable of extensions to validate against (or self.extensions)
165 165 """
166 166 def normalize_ext(_ext):
167 167 if _ext.startswith('.'):
168 168 _ext = _ext[1:]
169 169 return _ext.lower()
170 170
171 171 extensions = extensions or self.extensions
172 172 if not extensions:
173 173 return True
174 174
175 175 ext = normalize_ext(ext)
176 176
177 177 return ext in [normalize_ext(x) for x in extensions]
178 178
179 179 def save_file(self, file_obj, filename, directory=None, extensions=None,
180 180 extra_metadata=None, max_filesize=None, randomized_name=True, **kwargs):
181 181 """
182 182 Saves a file object to the uploads location.
183 183 Returns the resolved filename, i.e. the directory +
184 184 the (randomized/incremented) base name.
185 185
186 186 :param file_obj: **cgi.FieldStorage** object (or similar)
187 187 :param filename: original filename
188 188 :param directory: relative path of sub-directory
189 189 :param extensions: iterable of allowed extensions, if not default
190 190 :param max_filesize: maximum size of file that should be allowed
191 191 :param randomized_name: generate random generated UID or fixed based on the filename
192 192 :param extra_metadata: extra JSON metadata to store next to the file with .meta suffix
193 193
194 194 """
195 195
196 196 extensions = extensions or self.extensions
197 197
198 198 if not self.filename_allowed(filename, extensions):
199 199 raise FileNotAllowedException()
200 200
201 201 if directory:
202 202 dest_directory = os.path.join(self.base_path, directory)
203 203 else:
204 204 dest_directory = self.base_path
205 205
206 206 safe_make_dirs(dest_directory)
207 207
208 208 uid_filename = utils.uid_filename(filename, randomized=randomized_name)
209 209
210 210 # resolve also produces special sub-dir for file optimized store
211 211 filename, path = self.resolve_name(uid_filename, dest_directory)
212 212 stored_file_dir = os.path.dirname(path)
213 213
214 214 no_body_seek = kwargs.pop('no_body_seek', False)
215 215 if no_body_seek:
216 216 pass
217 217 else:
218 218 file_obj.seek(0)
219 219
220 220 with open(path, "wb") as dest:
221 221 length = 256 * 1024
222 222 while 1:
223 223 buf = file_obj.read(length)
224 224 if not buf:
225 225 break
226 226 dest.write(buf)
227 227
228 228 metadata = {}
229 229 if extra_metadata:
230 230 metadata = extra_metadata
231 231
232 232 size = os.stat(path).st_size
233 233
234 234 if max_filesize and size > max_filesize:
235 235 # free up the copied file, and raise exc
236 236 os.remove(path)
237 237 raise FileOverSizeException()
238 238
239 239 file_hash = self.calculate_path_hash(path)
240 240
241 241 metadata.update({
242 242 "filename": filename,
243 243 "size": size,
244 244 "time": time.time(),
245 245 "sha256": file_hash,
246 246 "meta_ver": METADATA_VER
247 247 })
248 248
249 249 filename_meta = filename + '.meta'
250 250 with open(os.path.join(stored_file_dir, filename_meta), "wb") as dest_meta:
251 251 dest_meta.write(json.dumps(metadata))
252 252
253 253 if directory:
254 254 filename = os.path.join(directory, filename)
255 255
256 256 return filename, metadata
257 257
258 def get_metadata(self, filename):
258 def get_metadata(self, filename, ignore_missing=False):
259 259 """
260 260 Reads JSON stored metadata for a file
261 261
262 262 :param filename:
263 263 :return:
264 264 """
265 265 filename = self.store_path(filename)
266 266 filename_meta = filename + '.meta'
267
267 if ignore_missing and not os.path.isfile(filename_meta):
268 return {}
268 269 with open(filename_meta, "rb") as source_meta:
269 270 return json.loads(source_meta.read())
@@ -1,405 +1,411 b''
1 1
2 2 /******************************************************************************
3 3 * *
4 4 * DO NOT CHANGE THIS FILE MANUALLY *
5 5 * *
6 6 * *
7 7 * This file is automatically generated when the app starts up with *
8 8 * generate_js_files = true *
9 9 * *
10 10 * To add a route here pass jsroute=True to the route definition in the app *
11 11 * *
12 12 ******************************************************************************/
13 13 function registerRCRoutes() {
14 14 // routes registration
15 pyroutes.register('admin_artifacts', '/_admin/artifacts', []);
16 pyroutes.register('admin_artifacts_data', '/_admin/artifacts-data', []);
17 pyroutes.register('admin_artifacts_delete', '/_admin/artifacts/%(uid)s/delete', ['uid']);
18 pyroutes.register('admin_artifacts_show_all', '/_admin/artifacts', []);
19 pyroutes.register('admin_artifacts_show_info', '/_admin/artifacts/%(uid)s', ['uid']);
20 pyroutes.register('admin_artifacts_update', '/_admin/artifacts/%(uid)s/update', ['uid']);
15 21 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
16 22 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
17 23 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
18 24 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
19 25 pyroutes.register('admin_home', '/_admin', []);
20 26 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
21 27 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
22 28 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
23 29 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
24 30 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
25 31 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
26 32 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
27 33 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
28 34 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
29 35 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
30 36 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
31 37 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
32 38 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
33 39 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
34 40 pyroutes.register('admin_settings', '/_admin/settings', []);
35 41 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
36 42 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
37 43 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
38 44 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
39 45 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
40 46 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
41 47 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions_delete_all', []);
42 48 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
43 49 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
44 50 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
45 51 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
46 52 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
47 53 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
48 54 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
49 55 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
50 56 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
51 57 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
52 58 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
53 59 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
54 60 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
55 61 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
56 62 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
57 63 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
58 64 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
59 65 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
60 66 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
61 67 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
62 68 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
63 69 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
64 70 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
65 71 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
66 72 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
67 73 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
68 74 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
69 75 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
70 76 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
71 77 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
72 78 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
73 79 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
74 80 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
75 81 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
76 82 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
77 83 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
78 84 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
79 85 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
80 86 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
81 87 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
82 88 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
83 89 pyroutes.register('apiv2', '/_admin/api', []);
84 90 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
85 91 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
86 92 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
87 93 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
88 94 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
89 95 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
90 96 pyroutes.register('channelstream_proxy', '/_channelstream', []);
91 97 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
92 98 pyroutes.register('commit_draft_comments_submit', '/%(repo_name)s/changeset/%(commit_id)s/draft_comments_submit', ['repo_name', 'commit_id']);
93 99 pyroutes.register('debug_style_email', '/_admin/debug_style/email/%(email_id)s', ['email_id']);
94 100 pyroutes.register('debug_style_email_plain_rendered', '/_admin/debug_style/email-rendered/%(email_id)s', ['email_id']);
95 101 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
96 102 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
97 103 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
98 104 pyroutes.register('download_file_by_token', '/_file_store/token-download/%(_auth_token)s/%(fid)s', ['_auth_token', 'fid']);
99 105 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
100 106 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
101 107 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
102 108 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
103 109 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
104 110 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
105 111 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
106 112 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
107 113 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
108 114 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
109 115 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
110 116 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
111 117 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
112 118 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
113 119 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
114 120 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
115 121 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
116 122 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
117 123 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
118 124 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
119 125 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
120 126 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
121 127 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
122 128 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
123 129 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
124 130 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
125 131 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
126 132 pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']);
127 133 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
128 134 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
129 135 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
130 136 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
131 137 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
132 138 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
133 139 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
134 140 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
135 141 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
136 142 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
137 143 pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']);
138 144 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
139 145 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
140 146 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
141 147 pyroutes.register('edit_user_auth_tokens_view', '/_admin/users/%(user_id)s/edit/auth_tokens/view', ['user_id']);
142 148 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
143 149 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
144 150 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
145 151 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
146 152 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
147 153 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
148 154 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
149 155 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
150 156 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
151 157 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
152 158 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
153 159 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
154 160 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
155 161 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
156 162 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
157 163 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
158 164 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
159 165 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
160 166 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
161 167 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
162 168 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
163 169 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
164 170 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
165 171 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
166 172 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
167 173 pyroutes.register('favicon', '/favicon.ico', []);
168 174 pyroutes.register('file_preview', '/_file_preview', []);
169 175 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
170 176 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
171 177 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
172 178 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
173 179 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
174 180 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/rev/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
175 181 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/rev/%(revision)s', ['gist_id', 'revision']);
176 182 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
177 183 pyroutes.register('gists_create', '/_admin/gists/create', []);
178 184 pyroutes.register('gists_new', '/_admin/gists/new', []);
179 185 pyroutes.register('gists_show', '/_admin/gists', []);
180 186 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
181 187 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
182 188 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
183 189 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
184 190 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
185 191 pyroutes.register('goto_switcher_data', '/_goto_data', []);
186 192 pyroutes.register('home', '/', []);
187 193 pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
188 194 pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
189 195 pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
190 196 pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
191 197 pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']);
192 198 pyroutes.register('journal', '/_admin/journal', []);
193 199 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
194 200 pyroutes.register('journal_public', '/_admin/public_journal', []);
195 201 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
196 202 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
197 203 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
198 204 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
199 205 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
200 206 pyroutes.register('login', '/_admin/login', []);
201 207 pyroutes.register('logout', '/_admin/logout', []);
202 208 pyroutes.register('main_page_repo_groups_data', '/_home_repo_groups', []);
203 209 pyroutes.register('main_page_repos_data', '/_home_repos', []);
204 210 pyroutes.register('markup_preview', '/_markup_preview', []);
205 211 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
206 212 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
207 213 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
208 214 pyroutes.register('my_account_auth_tokens_view', '/_admin/my_account/auth_tokens/view', []);
209 215 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
210 216 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
211 217 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
212 218 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
213 219 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
214 220 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
215 221 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
216 222 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
217 223 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
218 224 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
219 225 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
220 226 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
221 227 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
222 228 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
223 229 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
224 230 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
225 231 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
226 232 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
227 233 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
228 234 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
229 235 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
230 236 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
231 237 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
232 238 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
233 239 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
234 240 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
235 241 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
236 242 pyroutes.register('notifications_mark_all_read', '/_admin/notifications_mark_all_read', []);
237 243 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
238 244 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
239 245 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
240 246 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
241 247 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
242 248 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
243 249 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
244 250 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
245 251 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
246 252 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
247 253 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
248 254 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
249 255 pyroutes.register('pullrequest_comment_edit', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/edit', ['repo_name', 'pull_request_id', 'comment_id']);
250 256 pyroutes.register('pullrequest_comments', '/%(repo_name)s/pull-request/%(pull_request_id)s/comments', ['repo_name', 'pull_request_id']);
251 257 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
252 258 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
253 259 pyroutes.register('pullrequest_draft_comments_submit', '/%(repo_name)s/pull-request/%(pull_request_id)s/draft_comments_submit', ['repo_name', 'pull_request_id']);
254 260 pyroutes.register('pullrequest_drafts', '/%(repo_name)s/pull-request/%(pull_request_id)s/drafts', ['repo_name', 'pull_request_id']);
255 261 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
256 262 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
257 263 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
258 264 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
259 265 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
260 266 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
261 267 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
262 268 pyroutes.register('pullrequest_todos', '/%(repo_name)s/pull-request/%(pull_request_id)s/todos', ['repo_name', 'pull_request_id']);
263 269 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
264 270 pyroutes.register('register', '/_admin/register', []);
265 271 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
266 272 pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']);
267 273 pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']);
268 274 pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']);
269 275 pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']);
270 276 pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']);
271 277 pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']);
272 278 pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']);
273 279 pyroutes.register('repo_artifacts_stream_script', '/_file_store/stream-upload-script', []);
274 280 pyroutes.register('repo_artifacts_stream_store', '/_file_store/stream-upload', []);
275 281 pyroutes.register('repo_artifacts_update', '/%(repo_name)s/artifacts/update/%(uid)s', ['repo_name', 'uid']);
276 282 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
277 283 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
278 284 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
279 285 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
280 286 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
281 287 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
282 288 pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']);
283 289 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
284 290 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
285 291 pyroutes.register('repo_commit_comment_edit', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/edit', ['repo_name', 'commit_id', 'comment_id']);
286 292 pyroutes.register('repo_commit_comment_history_view', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_history_id)s/history_view', ['repo_name', 'commit_id', 'comment_history_id']);
287 293 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
288 294 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
289 295 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
290 296 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
291 297 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
292 298 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
293 299 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
294 300 pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']);
295 301 pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']);
296 302 pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
297 303 pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
298 304 pyroutes.register('repo_compare', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
299 305 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
300 306 pyroutes.register('repo_create', '/_admin/repos/create', []);
301 307 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
302 308 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
303 309 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
304 310 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
305 311 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
306 312 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
307 313 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
308 314 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
309 315 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
310 316 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
311 317 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
312 318 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
313 319 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
314 320 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
315 321 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
316 322 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
317 323 pyroutes.register('repo_files_check_head', '/%(repo_name)s/check_head/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
318 324 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
319 325 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
320 326 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
321 327 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
322 328 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
323 329 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
324 330 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
325 331 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
326 332 pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
327 333 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
328 334 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
329 335 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
330 336 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
331 337 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
332 338 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
333 339 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
334 340 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
335 341 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
336 342 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
337 343 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
338 344 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
339 345 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
340 346 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
341 347 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
342 348 pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []);
343 349 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
344 350 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
345 351 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
346 352 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
347 353 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
348 354 pyroutes.register('repo_list_data', '/_repos', []);
349 355 pyroutes.register('repo_new', '/_admin/repos/new', []);
350 356 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
351 357 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
352 358 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
353 359 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
354 360 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
355 361 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
356 362 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
357 363 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
358 364 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
359 365 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
360 366 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
361 367 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
362 368 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
363 369 pyroutes.register('repos', '/_admin/repos', []);
364 370 pyroutes.register('repos_data', '/_admin/repos_data', []);
365 371 pyroutes.register('reset_password', '/_admin/password_reset', []);
366 372 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
367 373 pyroutes.register('robots', '/robots.txt', []);
368 374 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']);
369 375 pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']);
370 376 pyroutes.register('search', '/_admin/search', []);
371 377 pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']);
372 378 pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']);
373 379 pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']);
374 380 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
375 381 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
376 382 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
377 383 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
378 384 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
379 385 pyroutes.register('upload_file', '/_file_store/upload', []);
380 386 pyroutes.register('user_autocomplete_data', '/_users', []);
381 387 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
382 388 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
383 389 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
384 390 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
385 391 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
386 392 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
387 393 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
388 394 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
389 395 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
390 396 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
391 397 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
392 398 pyroutes.register('user_groups', '/_admin/user_groups', []);
393 399 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
394 400 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
395 401 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
396 402 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
397 403 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
398 404 pyroutes.register('user_notice_dismiss', '/_admin/users/%(user_id)s/notice_dismiss', ['user_id']);
399 405 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
400 406 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
401 407 pyroutes.register('users', '/_admin/users', []);
402 408 pyroutes.register('users_create', '/_admin/users/create', []);
403 409 pyroutes.register('users_data', '/_admin/users_data', []);
404 410 pyroutes.register('users_new', '/_admin/users/new', []);
405 411 }
@@ -1,1262 +1,1263 b''
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 <%!
4 4 from rhodecode.lib import html_filters
5 5 %>
6 6
7 7 <%inherit file="root.mako"/>
8 8
9 9 <%include file="/ejs_templates/templates.html"/>
10 10
11 11 <div class="outerwrapper">
12 12 <!-- HEADER -->
13 13 <div class="header">
14 14 <div id="header-inner" class="wrapper">
15 15 <div id="logo">
16 16 <div class="logo-wrapper">
17 17 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
18 18 </div>
19 19 % if c.rhodecode_name:
20 20 <div class="branding">
21 21 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
22 22 </div>
23 23 % endif
24 24 </div>
25 25 <!-- MENU BAR NAV -->
26 26 ${self.menu_bar_nav()}
27 27 <!-- END MENU BAR NAV -->
28 28 </div>
29 29 </div>
30 30 ${self.menu_bar_subnav()}
31 31 <!-- END HEADER -->
32 32
33 33 <!-- CONTENT -->
34 34 <div id="content" class="wrapper">
35 35
36 36 <rhodecode-toast id="notifications"></rhodecode-toast>
37 37
38 38 <div class="main">
39 39 ${next.main()}
40 40 </div>
41 41
42 42 </div>
43 43 <!-- END CONTENT -->
44 44
45 45 </div>
46 46
47 47 <!-- FOOTER -->
48 48 <div id="footer">
49 49 <div id="footer-inner" class="title wrapper">
50 50 <div>
51 51 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
52 52
53 53 <p class="footer-link-right">
54 54 <a class="grey-link-action" href="${h.route_path('home', _query={'showrcid': 1})}">
55 55 RhodeCode
56 56 % if c.visual.show_version:
57 57 ${c.rhodecode_version}
58 58 % endif
59 59 ${c.rhodecode_edition}
60 60 </a> |
61 61
62 62 % if c.visual.rhodecode_support_url:
63 63 <a class="grey-link-action" href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a> |
64 64 <a class="grey-link-action" href="https://docs.rhodecode.com" target="_blank">${_('Documentation')}</a>
65 65 % endif
66 66
67 67 </p>
68 68
69 69 <p class="server-instance" style="display:${sid}">
70 70 ## display hidden instance ID if specially defined
71 71 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
72 72 % if c.rhodecode_instanceid:
73 73 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
74 74 % endif
75 75 </p>
76 76 </div>
77 77 </div>
78 78 </div>
79 79
80 80 <!-- END FOOTER -->
81 81
82 82 ### MAKO DEFS ###
83 83
84 84 <%def name="menu_bar_subnav()">
85 85 </%def>
86 86
87 87 <%def name="breadcrumbs(class_='breadcrumbs')">
88 88 <div class="${class_}">
89 89 ${self.breadcrumbs_links()}
90 90 </div>
91 91 </%def>
92 92
93 93 <%def name="admin_menu(active=None)">
94 94
95 95 <div id="context-bar">
96 96 <div class="wrapper">
97 97 <div class="title">
98 98 <div class="title-content">
99 99 <div class="title-main">
100 100 % if c.is_super_admin:
101 101 ${_('Super-admin Panel')}
102 102 % else:
103 103 ${_('Delegated Admin Panel')}
104 104 % endif
105 105 </div>
106 106 </div>
107 107 </div>
108 108
109 109 <ul id="context-pages" class="navigation horizontal-list">
110 110
111 111 ## super-admin case
112 112 % if c.is_super_admin:
113 113 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
114 114 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
115 115 <li class="${h.is_active('repository_groups', active)}"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
116 116 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
117 117 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
118 <li class="${h.is_active('artifacts', active)}"><a href="${h.route_path('admin_artifacts')}">${_('Artifacts')}</a></li>
118 119 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
119 120 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
120 121 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
121 122 <li class="${h.is_active('defaults', active)}"><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
122 123 <li class="${h.is_active('settings', active)}"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
123 124
124 125 ## delegated admin
125 126 % elif c.is_delegated_admin:
126 127 <%
127 128 repositories=c.auth_user.repositories_admin or c.can_create_repo
128 129 repository_groups=c.auth_user.repository_groups_admin or c.can_create_repo_group
129 130 user_groups=c.auth_user.user_groups_admin or c.can_create_user_group
130 131 %>
131 132
132 133 %if repositories:
133 134 <li class="${h.is_active('repositories', active)} local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
134 135 %endif
135 136 %if repository_groups:
136 137 <li class="${h.is_active('repository_groups', active)} local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
137 138 %endif
138 139 %if user_groups:
139 140 <li class="${h.is_active('user_groups', active)} local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
140 141 %endif
141 142 % endif
142 143 </ul>
143 144
144 145 </div>
145 146 <div class="clear"></div>
146 147 </div>
147 148 </%def>
148 149
149 150 <%def name="dt_info_panel(elements)">
150 151 <dl class="dl-horizontal">
151 152 %for dt, dd, title, show_items in elements:
152 153 <dt>${dt}:</dt>
153 154 <dd title="${h.tooltip(title)}">
154 155 %if callable(dd):
155 156 ## allow lazy evaluation of elements
156 157 ${dd()}
157 158 %else:
158 159 ${dd}
159 160 %endif
160 161 %if show_items:
161 162 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
162 163 %endif
163 164 </dd>
164 165
165 166 %if show_items:
166 167 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
167 168 %for item in show_items:
168 169 <dt></dt>
169 170 <dd>${item}</dd>
170 171 %endfor
171 172 </div>
172 173 %endif
173 174
174 175 %endfor
175 176 </dl>
176 177 </%def>
177 178
178 179 <%def name="tr_info_entry(element)">
179 180 <% key, val, title, show_items = element %>
180 181
181 182 <tr>
182 183 <td style="vertical-align: top">${key}</td>
183 184 <td title="${h.tooltip(title)}">
184 185 %if callable(val):
185 186 ## allow lazy evaluation of elements
186 187 ${val()}
187 188 %else:
188 189 ${val}
189 190 %endif
190 191 %if show_items:
191 192 <div class="collapsable-content" data-toggle="item-${h.md5_safe(val)[:6]}-details" style="display: none">
192 193 % for item in show_items:
193 194 <dt></dt>
194 195 <dd>${item}</dd>
195 196 % endfor
196 197 </div>
197 198 %endif
198 199 </td>
199 200 <td style="vertical-align: top">
200 201 %if show_items:
201 202 <span class="btn-collapse" data-toggle="item-${h.md5_safe(val)[:6]}-details">${_('Show More')} </span>
202 203 %endif
203 204 </td>
204 205 </tr>
205 206
206 207 </%def>
207 208
208 209 <%def name="gravatar(email, size=16, tooltip=False, tooltip_alt=None, user=None, extra_class=None)">
209 210 <%
210 211 if size > 16:
211 212 gravatar_class = ['gravatar','gravatar-large']
212 213 else:
213 214 gravatar_class = ['gravatar']
214 215
215 216 data_hovercard_url = ''
216 217 data_hovercard_alt = tooltip_alt.replace('<', '&lt;').replace('>', '&gt;') if tooltip_alt else ''
217 218
218 219 if tooltip:
219 220 gravatar_class += ['tooltip-hovercard']
220 221 if extra_class:
221 222 gravatar_class += extra_class
222 223 if tooltip and user:
223 224 if user.username == h.DEFAULT_USER:
224 225 gravatar_class.pop(-1)
225 226 else:
226 227 data_hovercard_url = request.route_path('hovercard_user', user_id=getattr(user, 'user_id', ''))
227 228 gravatar_class = ' '.join(gravatar_class)
228 229
229 230 %>
230 231 <%doc>
231 232 TODO: johbo: For now we serve double size images to make it smooth
232 233 for retina. This is how it worked until now. Should be replaced
233 234 with a better solution at some point.
234 235 </%doc>
235 236
236 237 <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)}" />
237 238 </%def>
238 239
239 240
240 241 <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False, _class='rc-user')">
241 242 <%
242 243 email = h.email_or_none(contact)
243 244 rc_user = h.discover_user(contact)
244 245 %>
245 246
246 247 <div class="${_class}">
247 248 ${self.gravatar(email, size, tooltip=tooltip, tooltip_alt=contact, user=rc_user)}
248 249 <span class="${('user user-disabled' if show_disabled else 'user')}">
249 250 ${h.link_to_user(rc_user or contact)}
250 251 </span>
251 252 </div>
252 253 </%def>
253 254
254 255
255 256 <%def name="user_group_icon(user_group=None, size=16, tooltip=False)">
256 257 <%
257 258 if (size > 16):
258 259 gravatar_class = 'icon-user-group-alt'
259 260 else:
260 261 gravatar_class = 'icon-user-group-alt'
261 262
262 263 if tooltip:
263 264 gravatar_class += ' tooltip-hovercard'
264 265
265 266 data_hovercard_url = request.route_path('hovercard_user_group', user_group_id=user_group.users_group_id)
266 267 %>
267 268 <%doc>
268 269 TODO: johbo: For now we serve double size images to make it smooth
269 270 for retina. This is how it worked until now. Should be replaced
270 271 with a better solution at some point.
271 272 </%doc>
272 273
273 274 <i style="font-size: ${size}px" class="${gravatar_class} x-icon-size-${size}" data-hovercard-url="${data_hovercard_url}"></i>
274 275 </%def>
275 276
276 277 <%def name="repo_page_title(repo_instance)">
277 278 <div class="title-content repo-title">
278 279
279 280 <div class="title-main">
280 281 ## SVN/HG/GIT icons
281 282 %if h.is_hg(repo_instance):
282 283 <i class="icon-hg"></i>
283 284 %endif
284 285 %if h.is_git(repo_instance):
285 286 <i class="icon-git"></i>
286 287 %endif
287 288 %if h.is_svn(repo_instance):
288 289 <i class="icon-svn"></i>
289 290 %endif
290 291
291 292 ## public/private
292 293 %if repo_instance.private:
293 294 <i class="icon-repo-private"></i>
294 295 %else:
295 296 <i class="icon-repo-public"></i>
296 297 %endif
297 298
298 299 ## repo name with group name
299 300 ${h.breadcrumb_repo_link(repo_instance)}
300 301
301 302 ## Context Actions
302 303 <div class="pull-right">
303 304 %if c.rhodecode_user.username != h.DEFAULT_USER:
304 305 <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>
305 306
306 307 <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 '')}">
307 308 % if c.repository_is_user_following:
308 309 <i class="icon-eye-off"></i>${_('Unwatch')}
309 310 % else:
310 311 <i class="icon-eye"></i>${_('Watch')}
311 312 % endif
312 313
313 314 </a>
314 315 %else:
315 316 <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>
316 317 %endif
317 318 </div>
318 319
319 320 </div>
320 321
321 322 ## FORKED
322 323 %if repo_instance.fork:
323 324 <p class="discreet">
324 325 <i class="icon-code-fork"></i> ${_('Fork of')}
325 326 ${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))}
326 327 </p>
327 328 %endif
328 329
329 330 ## IMPORTED FROM REMOTE
330 331 %if repo_instance.clone_uri:
331 332 <p class="discreet">
332 333 <i class="icon-code-fork"></i> ${_('Clone from')}
333 334 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
334 335 </p>
335 336 %endif
336 337
337 338 ## LOCKING STATUS
338 339 %if repo_instance.locked[0]:
339 340 <p class="locking_locked discreet">
340 341 <i class="icon-repo-lock"></i>
341 342 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
342 343 </p>
343 344 %elif repo_instance.enable_locking:
344 345 <p class="locking_unlocked discreet">
345 346 <i class="icon-repo-unlock"></i>
346 347 ${_('Repository not locked. Pull repository to lock it.')}
347 348 </p>
348 349 %endif
349 350
350 351 </div>
351 352 </%def>
352 353
353 354 <%def name="repo_menu(active=None)">
354 355 <%
355 356 ## determine if we have "any" option available
356 357 can_lock = h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking
357 358 has_actions = can_lock
358 359
359 360 %>
360 361 % if c.rhodecode_db_repo.archived:
361 362 <div class="alert alert-warning text-center">
362 363 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
363 364 </div>
364 365 % endif
365 366
366 367 <!--- REPO CONTEXT BAR -->
367 368 <div id="context-bar">
368 369 <div class="wrapper">
369 370
370 371 <div class="title">
371 372 ${self.repo_page_title(c.rhodecode_db_repo)}
372 373 </div>
373 374
374 375 <ul id="context-pages" class="navigation horizontal-list">
375 376 <li class="${h.is_active('summary', active)}"><a class="menulink" href="${h.route_path('repo_summary_explicit', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
376 377 <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>
377 378 <li class="${h.is_active('files', active)}"><a class="menulink" href="${h.repo_files_by_ref_url(c.repo_name, c.rhodecode_db_repo.repo_type, f_path='', ref_name=c.rhodecode_db_repo.landing_ref_name, commit_id='tip', query={'at':c.rhodecode_db_repo.landing_ref_name})}"><div class="menulabel">${_('Files')}</div></a></li>
378 379 <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>
379 380
380 381 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
381 382 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
382 383 <li class="${h.is_active('showpullrequest', active)}">
383 384 <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)}">
384 385 <div class="menulabel">
385 386 ${_('Pull Requests')} <span class="menulink-counter">${c.repository_pull_requests}</span>
386 387 </div>
387 388 </a>
388 389 </li>
389 390 %endif
390 391
391 392 <li class="${h.is_active('artifacts', active)}">
392 393 <a class="menulink" href="${h.route_path('repo_artifacts_list',repo_name=c.repo_name)}">
393 394 <div class="menulabel">
394 395 ${_('Artifacts')} <span class="menulink-counter">${c.repository_artifacts}</span>
395 396 </div>
396 397 </a>
397 398 </li>
398 399
399 400 %if not c.rhodecode_db_repo.archived and h.HasRepoPermissionAll('repository.admin')(c.repo_name):
400 401 <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>
401 402 %endif
402 403
403 404 <li class="${h.is_active('options', active)}">
404 405 % if has_actions:
405 406 <a class="menulink dropdown">
406 407 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
407 408 </a>
408 409 <ul class="submenu">
409 410 %if can_lock:
410 411 %if c.rhodecode_db_repo.locked[0]:
411 412 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock Repository')}</a></li>
412 413 %else:
413 414 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock Repository')}</a></li>
414 415 %endif
415 416 %endif
416 417 </ul>
417 418 % endif
418 419 </li>
419 420
420 421 </ul>
421 422 </div>
422 423 <div class="clear"></div>
423 424 </div>
424 425
425 426 <!--- REPO END CONTEXT BAR -->
426 427
427 428 </%def>
428 429
429 430 <%def name="repo_group_page_title(repo_group_instance)">
430 431 <div class="title-content">
431 432 <div class="title-main">
432 433 ## Repository Group icon
433 434 <i class="icon-repo-group"></i>
434 435
435 436 ## repo name with group name
436 437 ${h.breadcrumb_repo_group_link(repo_group_instance)}
437 438 </div>
438 439
439 440 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
440 441 <div class="repo-group-desc discreet">
441 442 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
442 443 </div>
443 444
444 445 </div>
445 446 </%def>
446 447
447 448
448 449 <%def name="repo_group_menu(active=None)">
449 450 <%
450 451 gr_name = c.repo_group.group_name if c.repo_group else None
451 452 # create repositories with write permission on group is set to true
452 453 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
453 454
454 455 %>
455 456
456 457
457 458 <!--- REPO GROUP CONTEXT BAR -->
458 459 <div id="context-bar">
459 460 <div class="wrapper">
460 461 <div class="title">
461 462 ${self.repo_group_page_title(c.repo_group)}
462 463 </div>
463 464
464 465 <ul id="context-pages" class="navigation horizontal-list">
465 466 <li class="${h.is_active('home', active)}">
466 467 <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>
467 468 </li>
468 469 % if c.is_super_admin or group_admin:
469 470 <li class="${h.is_active('settings', active)}">
470 471 <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>
471 472 </li>
472 473 % endif
473 474
474 475 </ul>
475 476 </div>
476 477 <div class="clear"></div>
477 478 </div>
478 479
479 480 <!--- REPO GROUP CONTEXT BAR -->
480 481
481 482 </%def>
482 483
483 484
484 485 <%def name="usermenu(active=False)">
485 486 <%
486 487 not_anonymous = c.rhodecode_user.username != h.DEFAULT_USER
487 488
488 489 gr_name = c.repo_group.group_name if (hasattr(c, 'repo_group') and c.repo_group) else None
489 490 # create repositories with write permission on group is set to true
490 491
491 492 can_fork = c.is_super_admin or h.HasPermissionAny('hg.fork.repository')()
492 493 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
493 494 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
494 495 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
495 496
496 497 can_create_repos = c.is_super_admin or c.can_create_repo
497 498 can_create_repo_groups = c.is_super_admin or c.can_create_repo_group
498 499
499 500 can_create_repos_in_group = c.is_super_admin or group_admin or (group_write and create_on_write)
500 501 can_create_repo_groups_in_group = c.is_super_admin or group_admin
501 502 %>
502 503
503 504 % if not_anonymous:
504 505 <%
505 506 default_target_group = dict()
506 507 if c.rhodecode_user.personal_repo_group:
507 508 default_target_group = dict(parent_group=c.rhodecode_user.personal_repo_group.group_id)
508 509 %>
509 510
510 511 ## create action
511 512 <li>
512 513 <a href="#create-actions" onclick="return false;" class="menulink childs">
513 514 <i class="icon-plus-circled"></i>
514 515 </a>
515 516
516 517 <div class="action-menu submenu">
517 518
518 519 <ol>
519 520 ## scope of within a repository
520 521 % if hasattr(c, 'rhodecode_db_repo') and c.rhodecode_db_repo:
521 522 <li class="submenu-title">${_('This Repository')}</li>
522 523 <li>
523 524 <a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a>
524 525 </li>
525 526 % if can_fork:
526 527 <li>
527 528 <a href="${h.route_path('repo_fork_new',repo_name=c.repo_name,_query=default_target_group)}">${_('Fork this repository')}</a>
528 529 </li>
529 530 % endif
530 531 % endif
531 532
532 533 ## scope of within repository groups
533 534 % if hasattr(c, 'repo_group') and c.repo_group and (can_create_repos_in_group or can_create_repo_groups_in_group):
534 535 <li class="submenu-title">${_('This Repository Group')}</li>
535 536
536 537 % if can_create_repos_in_group:
537 538 <li>
538 539 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('New Repository')}</a>
539 540 </li>
540 541 % endif
541 542
542 543 % if can_create_repo_groups_in_group:
543 544 <li>
544 545 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'New Repository Group')}</a>
545 546 </li>
546 547 % endif
547 548 % endif
548 549
549 550 ## personal group
550 551 % if c.rhodecode_user.personal_repo_group:
551 552 <li class="submenu-title">Personal Group</li>
552 553
553 554 <li>
554 555 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}" >${_('New Repository')} </a>
555 556 </li>
556 557
557 558 <li>
558 559 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}">${_('New Repository Group')} </a>
559 560 </li>
560 561 % endif
561 562
562 563 ## Global actions
563 564 <li class="submenu-title">RhodeCode</li>
564 565 % if can_create_repos:
565 566 <li>
566 567 <a href="${h.route_path('repo_new')}" >${_('New Repository')}</a>
567 568 </li>
568 569 % endif
569 570
570 571 % if can_create_repo_groups:
571 572 <li>
572 573 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
573 574 </li>
574 575 % endif
575 576
576 577 <li>
577 578 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
578 579 </li>
579 580
580 581 </ol>
581 582
582 583 </div>
583 584 </li>
584 585
585 586 ## notifications
586 587 <li>
587 588 <a class="${('empty' if c.unread_notifications == 0 else '')}" href="${h.route_path('notifications_show_all')}">
588 589 ${c.unread_notifications}
589 590 </a>
590 591 </li>
591 592 % endif
592 593
593 594 ## USER MENU
594 595 <li id="quick_login_li" class="${'active' if active else ''}">
595 596 % if c.rhodecode_user.username == h.DEFAULT_USER:
596 597 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
597 598 ${gravatar(c.rhodecode_user.email, 20)}
598 599 <span class="user">
599 600 <span>${_('Sign in')}</span>
600 601 </span>
601 602 </a>
602 603 % else:
603 604 ## logged in user
604 605 <a id="quick_login_link" class="menulink childs">
605 606 ${gravatar(c.rhodecode_user.email, 20)}
606 607 <span class="user">
607 608 <span class="menu_link_user">${c.rhodecode_user.username}</span>
608 609 <div class="show_more"></div>
609 610 </span>
610 611 </a>
611 612 ## subnav with menu for logged in user
612 613 <div class="user-menu submenu">
613 614 <div id="quick_login">
614 615 %if c.rhodecode_user.username != h.DEFAULT_USER:
615 616 <div class="">
616 617 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
617 618 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
618 619 <div class="email">${c.rhodecode_user.email}</div>
619 620 </div>
620 621 <div class="">
621 622 <ol class="links">
622 623 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
623 624 % if c.rhodecode_user.personal_repo_group:
624 625 <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>
625 626 % endif
626 627 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
627 628
628 629 % if c.debug_style:
629 630 <li>
630 631 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
631 632 <div class="menulabel">${_('[Style]')}</div>
632 633 </a>
633 634 </li>
634 635 % endif
635 636
636 637 ## bookmark-items
637 638 <li class="bookmark-items">
638 639 ${_('Bookmarks')}
639 640 <div class="pull-right">
640 641 <a href="${h.route_path('my_account_bookmarks')}">
641 642
642 643 <i class="icon-cog"></i>
643 644 </a>
644 645 </div>
645 646 </li>
646 647 % if not c.bookmark_items:
647 648 <li>
648 649 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
649 650 </li>
650 651 % endif
651 652 % for item in c.bookmark_items:
652 653 <li>
653 654 % if item.repository:
654 655 <div>
655 656 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
656 657 <code>${item.position}</code>
657 658 % if item.repository.repo_type == 'hg':
658 659 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
659 660 % elif item.repository.repo_type == 'git':
660 661 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
661 662 % elif item.repository.repo_type == 'svn':
662 663 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
663 664 % endif
664 665 ${(item.title or h.shorter(item.repository.repo_name, 30))}
665 666 </a>
666 667 </div>
667 668 % elif item.repository_group:
668 669 <div>
669 670 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
670 671 <code>${item.position}</code>
671 672 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
672 673 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
673 674 </a>
674 675 </div>
675 676 % else:
676 677 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
677 678 <code>${item.position}</code>
678 679 ${item.title}
679 680 </a>
680 681 % endif
681 682 </li>
682 683 % endfor
683 684
684 685 <li class="logout">
685 686 ${h.secure_form(h.route_path('logout'), request=request)}
686 687 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
687 688 ${h.end_form()}
688 689 </li>
689 690 </ol>
690 691 </div>
691 692 %endif
692 693 </div>
693 694 </div>
694 695
695 696 % endif
696 697 </li>
697 698 </%def>
698 699
699 700 <%def name="menu_items(active=None)">
700 701 <%
701 702 notice_messages, notice_level = c.rhodecode_user.get_notice_messages()
702 703 notice_display = 'none' if len(notice_messages) == 0 else ''
703 704 %>
704 705
705 706 <ul id="quick" class="main_nav navigation horizontal-list">
706 707 ## notice box for important system messages
707 708 <li style="display: ${notice_display}">
708 709 <a class="notice-box" href="#openNotice" onclick="$('.notice-messages-container').toggle(); return false">
709 710 <div class="menulabel-notice ${notice_level}" >
710 711 ${len(notice_messages)}
711 712 </div>
712 713 </a>
713 714 </li>
714 715 <div class="notice-messages-container" style="display: none">
715 716 <div class="notice-messages">
716 717 <table class="rctable">
717 718 % for notice in notice_messages:
718 719 <tr id="notice-message-${notice['msg_id']}" class="notice-message-${notice['level']}">
719 720 <td style="vertical-align: text-top; width: 20px">
720 721 <i class="tooltip icon-info notice-color-${notice['level']}" title="${notice['level']}"></i>
721 722 </td>
722 723 <td>
723 724 <span><i class="icon-plus-squared cursor-pointer" onclick="$('#notice-${notice['msg_id']}').toggle()"></i> </span>
724 725 ${notice['subject']}
725 726
726 727 <div id="notice-${notice['msg_id']}" style="display: none">
727 728 ${h.render(notice['body'], renderer='markdown')}
728 729 </div>
729 730 </td>
730 731 <td style="vertical-align: text-top; width: 35px;">
731 732 <a class="tooltip" title="${_('dismiss')}" href="#dismiss" onclick="dismissNotice(${notice['msg_id']});return false">
732 733 <i class="icon-remove icon-filled-red"></i>
733 734 </a>
734 735 </td>
735 736 </tr>
736 737
737 738 % endfor
738 739 </table>
739 740 </div>
740 741 </div>
741 742 ## Main filter
742 743 <li>
743 744 <div class="menulabel main_filter_box">
744 745 <div class="main_filter_input_box">
745 746 <ul class="searchItems">
746 747
747 748 <li class="searchTag searchTagIcon">
748 749 <i class="icon-search"></i>
749 750 </li>
750 751
751 752 % if c.template_context['search_context']['repo_id']:
752 753 <li class="searchTag searchTagFilter searchTagHidable" >
753 754 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
754 755 <span class="tag">
755 756 This repo
756 757 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
757 758 </span>
758 759 ##</a>
759 760 </li>
760 761 % elif c.template_context['search_context']['repo_group_id']:
761 762 <li class="searchTag searchTagFilter searchTagHidable">
762 763 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
763 764 <span class="tag">
764 765 This group
765 766 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
766 767 </span>
767 768 ##</a>
768 769 </li>
769 770 % endif
770 771
771 772 <li class="searchTagInput">
772 773 <input class="main_filter_input" id="main_filter" size="25" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
773 774 </li>
774 775 <li class="searchTag searchTagHelp">
775 776 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
776 777 </li>
777 778 </ul>
778 779 </div>
779 780 </div>
780 781
781 782 <div id="main_filter_help" style="display: none">
782 783 - Use '/' key to quickly access this field.
783 784
784 785 - Enter a name of repository, or repository group for quick search.
785 786
786 787 - Prefix query to allow special search:
787 788
788 789 <strong>user:</strong>admin, to search for usernames, always global
789 790
790 791 <strong>user_group:</strong>devops, to search for user groups, always global
791 792
792 793 <strong>pr:</strong>303, to search for pull request number, title, or description, always global
793 794
794 795 <strong>commit:</strong>efced4, to search for commits, scoped to repositories or groups
795 796
796 797 <strong>file:</strong>models.py, to search for file paths, scoped to repositories or groups
797 798
798 799 % if c.template_context['search_context']['repo_id']:
799 800 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>
800 801 % elif c.template_context['search_context']['repo_group_id']:
801 802 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>
802 803 % else:
803 804 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
804 805 % endif
805 806 </div>
806 807 </li>
807 808
808 809 ## ROOT MENU
809 810 <li class="${h.is_active('home', active)}">
810 811 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
811 812 <div class="menulabel">${_('Home')}</div>
812 813 </a>
813 814 </li>
814 815
815 816 %if c.rhodecode_user.username != h.DEFAULT_USER:
816 817 <li class="${h.is_active('journal', active)}">
817 818 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
818 819 <div class="menulabel">${_('Journal')}</div>
819 820 </a>
820 821 </li>
821 822 %else:
822 823 <li class="${h.is_active('journal', active)}">
823 824 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
824 825 <div class="menulabel">${_('Public journal')}</div>
825 826 </a>
826 827 </li>
827 828 %endif
828 829
829 830 <li class="${h.is_active('gists', active)}">
830 831 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
831 832 <div class="menulabel">${_('Gists')}</div>
832 833 </a>
833 834 </li>
834 835
835 836 % if c.is_super_admin or c.is_delegated_admin:
836 837 <li class="${h.is_active('admin', active)}">
837 838 <a class="menulink childs" title="${_('Admin settings')}" href="${h.route_path('admin_home')}">
838 839 <div class="menulabel">${_('Admin')} </div>
839 840 </a>
840 841 </li>
841 842 % endif
842 843
843 844 ## render extra user menu
844 845 ${usermenu(active=(active=='my_account'))}
845 846
846 847 </ul>
847 848
848 849 <script type="text/javascript">
849 850 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
850 851
851 852 var formatRepoResult = function(result, container, query, escapeMarkup) {
852 853 return function(data, escapeMarkup) {
853 854 if (!data.repo_id){
854 855 return data.text; // optgroup text Repositories
855 856 }
856 857
857 858 var tmpl = '';
858 859 var repoType = data['repo_type'];
859 860 var repoName = data['text'];
860 861
861 862 if(data && data.type == 'repo'){
862 863 if(repoType === 'hg'){
863 864 tmpl += '<i class="icon-hg"></i> ';
864 865 }
865 866 else if(repoType === 'git'){
866 867 tmpl += '<i class="icon-git"></i> ';
867 868 }
868 869 else if(repoType === 'svn'){
869 870 tmpl += '<i class="icon-svn"></i> ';
870 871 }
871 872 if(data['private']){
872 873 tmpl += '<i class="icon-lock" ></i> ';
873 874 }
874 875 else if(visualShowPublicIcon){
875 876 tmpl += '<i class="icon-unlock-alt"></i> ';
876 877 }
877 878 }
878 879 tmpl += escapeMarkup(repoName);
879 880 return tmpl;
880 881
881 882 }(result, escapeMarkup);
882 883 };
883 884
884 885 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
885 886 return function(data, escapeMarkup) {
886 887 if (!data.repo_group_id){
887 888 return data.text; // optgroup text Repositories
888 889 }
889 890
890 891 var tmpl = '';
891 892 var repoGroupName = data['text'];
892 893
893 894 if(data){
894 895
895 896 tmpl += '<i class="icon-repo-group"></i> ';
896 897
897 898 }
898 899 tmpl += escapeMarkup(repoGroupName);
899 900 return tmpl;
900 901
901 902 }(result, escapeMarkup);
902 903 };
903 904
904 905 var escapeRegExChars = function (value) {
905 906 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
906 907 };
907 908
908 909 var getRepoIcon = function(repo_type) {
909 910 if (repo_type === 'hg') {
910 911 return '<i class="icon-hg"></i> ';
911 912 }
912 913 else if (repo_type === 'git') {
913 914 return '<i class="icon-git"></i> ';
914 915 }
915 916 else if (repo_type === 'svn') {
916 917 return '<i class="icon-svn"></i> ';
917 918 }
918 919 return ''
919 920 };
920 921
921 922 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
922 923
923 924 if (value.split(':').length === 2) {
924 925 value = value.split(':')[1]
925 926 }
926 927
927 928 var searchType = data['type'];
928 929 var searchSubType = data['subtype'];
929 930 var valueDisplay = data['value_display'];
930 931 var valueIcon = data['value_icon'];
931 932
932 933 var pattern = '(' + escapeRegExChars(value) + ')';
933 934
934 935 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
935 936
936 937 // highlight match
937 938 if (searchType != 'text') {
938 939 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
939 940 }
940 941
941 942 var icon = '';
942 943
943 944 if (searchType === 'hint') {
944 945 icon += '<i class="icon-repo-group"></i> ';
945 946 }
946 947 // full text search/hints
947 948 else if (searchType === 'search') {
948 949 if (valueIcon === undefined) {
949 950 icon += '<i class="icon-more"></i> ';
950 951 } else {
951 952 icon += valueIcon + ' ';
952 953 }
953 954
954 955 if (searchSubType !== undefined && searchSubType == 'repo') {
955 956 valueDisplay += '<div class="pull-right tag">repository</div>';
956 957 }
957 958 else if (searchSubType !== undefined && searchSubType == 'repo_group') {
958 959 valueDisplay += '<div class="pull-right tag">repo group</div>';
959 960 }
960 961 }
961 962 // repository
962 963 else if (searchType === 'repo') {
963 964
964 965 var repoIcon = getRepoIcon(data['repo_type']);
965 966 icon += repoIcon;
966 967
967 968 if (data['private']) {
968 969 icon += '<i class="icon-lock" ></i> ';
969 970 }
970 971 else if (visualShowPublicIcon) {
971 972 icon += '<i class="icon-unlock-alt"></i> ';
972 973 }
973 974 }
974 975 // repository groups
975 976 else if (searchType === 'repo_group') {
976 977 icon += '<i class="icon-repo-group"></i> ';
977 978 }
978 979 // user group
979 980 else if (searchType === 'user_group') {
980 981 icon += '<i class="icon-group"></i> ';
981 982 }
982 983 // user
983 984 else if (searchType === 'user') {
984 985 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
985 986 }
986 987 // pull request
987 988 else if (searchType === 'pull_request') {
988 989 icon += '<i class="icon-merge"></i> ';
989 990 }
990 991 // commit
991 992 else if (searchType === 'commit') {
992 993 var repo_data = data['repo_data'];
993 994 var repoIcon = getRepoIcon(repo_data['repository_type']);
994 995 if (repoIcon) {
995 996 icon += repoIcon;
996 997 } else {
997 998 icon += '<i class="icon-tag"></i>';
998 999 }
999 1000 }
1000 1001 // file
1001 1002 else if (searchType === 'file') {
1002 1003 var repo_data = data['repo_data'];
1003 1004 var repoIcon = getRepoIcon(repo_data['repository_type']);
1004 1005 if (repoIcon) {
1005 1006 icon += repoIcon;
1006 1007 } else {
1007 1008 icon += '<i class="icon-tag"></i>';
1008 1009 }
1009 1010 }
1010 1011 // generic text
1011 1012 else if (searchType === 'text') {
1012 1013 icon = '';
1013 1014 }
1014 1015
1015 1016 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
1016 1017 return tmpl.format(icon, valueDisplay);
1017 1018 };
1018 1019
1019 1020 var handleSelect = function(element, suggestion) {
1020 1021 if (suggestion.type === "hint") {
1021 1022 // we skip action
1022 1023 $('#main_filter').focus();
1023 1024 }
1024 1025 else if (suggestion.type === "text") {
1025 1026 // we skip action
1026 1027 $('#main_filter').focus();
1027 1028
1028 1029 } else {
1029 1030 window.location = suggestion['url'];
1030 1031 }
1031 1032 };
1032 1033
1033 1034 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
1034 1035 if (queryLowerCase.split(':').length === 2) {
1035 1036 queryLowerCase = queryLowerCase.split(':')[1]
1036 1037 }
1037 1038 if (suggestion.type === "text") {
1038 1039 // special case we don't want to "skip" display for
1039 1040 return true
1040 1041 }
1041 1042 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
1042 1043 };
1043 1044
1044 1045 var cleanContext = {
1045 1046 repo_view_type: null,
1046 1047
1047 1048 repo_id: null,
1048 1049 repo_name: "",
1049 1050
1050 1051 repo_group_id: null,
1051 1052 repo_group_name: null
1052 1053 };
1053 1054 var removeGoToFilter = function () {
1054 1055 $('.searchTagHidable').hide();
1055 1056 $('#main_filter').autocomplete(
1056 1057 'setOptions', {params:{search_context: cleanContext}});
1057 1058 };
1058 1059
1059 1060 $('#main_filter').autocomplete({
1060 1061 serviceUrl: pyroutes.url('goto_switcher_data'),
1061 1062 params: {
1062 1063 "search_context": templateContext.search_context
1063 1064 },
1064 1065 minChars:2,
1065 1066 maxHeight:400,
1066 1067 deferRequestBy: 300, //miliseconds
1067 1068 tabDisabled: true,
1068 1069 autoSelectFirst: false,
1069 1070 containerClass: 'autocomplete-qfilter-suggestions',
1070 1071 formatResult: autocompleteMainFilterFormatResult,
1071 1072 lookupFilter: autocompleteMainFilterResult,
1072 1073 onSelect: function (element, suggestion) {
1073 1074 handleSelect(element, suggestion);
1074 1075 return false;
1075 1076 },
1076 1077 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
1077 1078 if (jqXHR !== 'abort') {
1078 1079 var message = formatErrorMessage(jqXHR, textStatus, errorThrown);
1079 1080 SwalNoAnimation.fire({
1080 1081 icon: 'error',
1081 1082 title: _gettext('Error during search operation'),
1082 1083 html: '<span style="white-space: pre-line">{0}</span>'.format(message),
1083 1084 }).then(function(result) {
1084 1085 window.location.reload();
1085 1086 })
1086 1087 }
1087 1088 },
1088 1089 onSearchStart: function (params) {
1089 1090 $('.searchTag.searchTagIcon').html('<i class="icon-spin animate-spin"></i>')
1090 1091 },
1091 1092 onSearchComplete: function (query, suggestions) {
1092 1093 $('.searchTag.searchTagIcon').html('<i class="icon-search"></i>')
1093 1094 },
1094 1095 });
1095 1096
1096 1097 showMainFilterBox = function () {
1097 1098 $('#main_filter_help').toggle();
1098 1099 };
1099 1100
1100 1101 $('#main_filter').on('keydown.autocomplete', function (e) {
1101 1102
1102 1103 var BACKSPACE = 8;
1103 1104 var el = $(e.currentTarget);
1104 1105 if(e.which === BACKSPACE){
1105 1106 var inputVal = el.val();
1106 1107 if (inputVal === ""){
1107 1108 removeGoToFilter()
1108 1109 }
1109 1110 }
1110 1111 });
1111 1112
1112 1113 var dismissNotice = function(noticeId) {
1113 1114
1114 1115 var url = pyroutes.url('user_notice_dismiss',
1115 1116 {"user_id": templateContext.rhodecode_user.user_id});
1116 1117
1117 1118 var postData = {
1118 1119 'csrf_token': CSRF_TOKEN,
1119 1120 'notice_id': noticeId,
1120 1121 };
1121 1122
1122 1123 var success = function(response) {
1123 1124 $('#notice-message-' + noticeId).remove();
1124 1125 return false;
1125 1126 };
1126 1127 var failure = function(data, textStatus, xhr) {
1127 1128 alert("error processing request: " + textStatus);
1128 1129 return false;
1129 1130 };
1130 1131 ajaxPOST(url, postData, success, failure);
1131 1132 }
1132 1133
1133 1134 var hideLicenseWarning = function () {
1134 1135 var fingerprint = templateContext.session_attrs.license_fingerprint;
1135 1136 storeUserSessionAttr('rc_user_session_attr.hide_license_warning', fingerprint);
1136 1137 $('#notifications').hide();
1137 1138 }
1138 1139
1139 1140 var hideLicenseError = function () {
1140 1141 var fingerprint = templateContext.session_attrs.license_fingerprint;
1141 1142 storeUserSessionAttr('rc_user_session_attr.hide_license_error', fingerprint);
1142 1143 $('#notifications').hide();
1143 1144 }
1144 1145
1145 1146 </script>
1146 1147 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
1147 1148 </%def>
1148 1149
1149 1150 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
1150 1151 <div class="modal-dialog">
1151 1152 <div class="modal-content">
1152 1153 <div class="modal-header">
1153 1154 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1154 1155 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
1155 1156 </div>
1156 1157 <div class="modal-body">
1157 1158 <div class="block-left">
1158 1159 <table class="keyboard-mappings">
1159 1160 <tbody>
1160 1161 <tr>
1161 1162 <th></th>
1162 1163 <th>${_('Site-wide shortcuts')}</th>
1163 1164 </tr>
1164 1165 <%
1165 1166 elems = [
1166 1167 ('/', 'Use quick search box'),
1167 1168 ('g h', 'Goto home page'),
1168 1169 ('g g', 'Goto my private gists page'),
1169 1170 ('g G', 'Goto my public gists page'),
1170 1171 ('g 0-9', 'Goto bookmarked items from 0-9'),
1171 1172 ('n r', 'New repository page'),
1172 1173 ('n g', 'New gist page'),
1173 1174 ]
1174 1175 %>
1175 1176 %for key, desc in elems:
1176 1177 <tr>
1177 1178 <td class="keys">
1178 1179 <span class="key tag">${key}</span>
1179 1180 </td>
1180 1181 <td>${desc}</td>
1181 1182 </tr>
1182 1183 %endfor
1183 1184 </tbody>
1184 1185 </table>
1185 1186 </div>
1186 1187 <div class="block-left">
1187 1188 <table class="keyboard-mappings">
1188 1189 <tbody>
1189 1190 <tr>
1190 1191 <th></th>
1191 1192 <th>${_('Repositories')}</th>
1192 1193 </tr>
1193 1194 <%
1194 1195 elems = [
1195 1196 ('g s', 'Goto summary page'),
1196 1197 ('g c', 'Goto changelog page'),
1197 1198 ('g f', 'Goto files page'),
1198 1199 ('g F', 'Goto files page with file search activated'),
1199 1200 ('g p', 'Goto pull requests page'),
1200 1201 ('g o', 'Goto repository settings'),
1201 1202 ('g O', 'Goto repository access permissions settings'),
1202 1203 ('t s', 'Toggle sidebar on some pages'),
1203 1204 ]
1204 1205 %>
1205 1206 %for key, desc in elems:
1206 1207 <tr>
1207 1208 <td class="keys">
1208 1209 <span class="key tag">${key}</span>
1209 1210 </td>
1210 1211 <td>${desc}</td>
1211 1212 </tr>
1212 1213 %endfor
1213 1214 </tbody>
1214 1215 </table>
1215 1216 </div>
1216 1217 </div>
1217 1218 <div class="modal-footer">
1218 1219 </div>
1219 1220 </div><!-- /.modal-content -->
1220 1221 </div><!-- /.modal-dialog -->
1221 1222 </div><!-- /.modal -->
1222 1223
1223 1224
1224 1225 <script type="text/javascript">
1225 1226 (function () {
1226 1227 "use sctrict";
1227 1228
1228 1229 // details block auto-hide menu
1229 1230 $(document).mouseup(function(e) {
1230 1231 var container = $('.details-inline-block');
1231 1232 if (!container.is(e.target) && container.has(e.target).length === 0) {
1232 1233 $('.details-inline-block[open]').removeAttr('open')
1233 1234 }
1234 1235 });
1235 1236
1236 1237 var $sideBar = $('.right-sidebar');
1237 1238 var expanded = $sideBar.hasClass('right-sidebar-expanded');
1238 1239 var sidebarState = templateContext.session_attrs.sidebarState;
1239 1240 var sidebarEnabled = $('aside.right-sidebar').get(0);
1240 1241
1241 1242 if (sidebarState === 'expanded') {
1242 1243 expanded = true
1243 1244 } else if (sidebarState === 'collapsed') {
1244 1245 expanded = false
1245 1246 }
1246 1247 if (sidebarEnabled) {
1247 1248 // show sidebar since it's hidden on load
1248 1249 $('.right-sidebar').show();
1249 1250
1250 1251 // init based on set initial class, or if defined user session attrs
1251 1252 if (expanded) {
1252 1253 window.expandSidebar();
1253 1254 window.updateStickyHeader();
1254 1255
1255 1256 } else {
1256 1257 window.collapseSidebar();
1257 1258 window.updateStickyHeader();
1258 1259 }
1259 1260 }
1260 1261 })()
1261 1262
1262 1263 </script>
@@ -1,492 +1,499 b''
1 1 ## DATA TABLE RE USABLE ELEMENTS
2 2 ## usage:
3 3 ## <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
4 4 <%namespace name="base" file="/base/base.mako"/>
5 5
6 6 <%def name="metatags_help()">
7 7 <table>
8 8 <%
9 9 example_tags = [
10 10 ('state','[stable]'),
11 11 ('state','[stale]'),
12 12 ('state','[featured]'),
13 13 ('state','[dev]'),
14 14 ('state','[dead]'),
15 15 ('state','[deprecated]'),
16 16
17 17 ('label','[personal]'),
18 18 ('generic','[v2.0.0]'),
19 19
20 20 ('lang','[lang =&gt; JavaScript]'),
21 21 ('license','[license =&gt; LicenseName]'),
22 22
23 23 ('ref','[requires =&gt; RepoName]'),
24 24 ('ref','[recommends =&gt; GroupName]'),
25 25 ('ref','[conflicts =&gt; SomeName]'),
26 26 ('ref','[base =&gt; SomeName]'),
27 27 ('url','[url =&gt; [linkName](https://rhodecode.com)]'),
28 28 ('see','[see =&gt; http://rhodecode.com]'),
29 29 ]
30 30 %>
31 31 % for tag_type, tag in example_tags:
32 32 <tr>
33 33 <td>${tag|n}</td>
34 34 <td>${h.style_metatag(tag_type, tag)|n}</td>
35 35 </tr>
36 36 % endfor
37 37 </table>
38 38 </%def>
39 39
40 40 <%def name="render_description(description, stylify_metatags)">
41 41 <%
42 42 tags = []
43 43 if stylify_metatags:
44 44 tags, description = h.extract_metatags(description)
45 45 %>
46 46 % for tag_type, tag in tags:
47 47 ${h.style_metatag(tag_type, tag)|n,trim}
48 48 % endfor
49 49 <code style="white-space: pre-wrap">${description}</code>
50 50 </%def>
51 51
52 52 ## REPOSITORY RENDERERS
53 53 <%def name="quick_menu(repo_name)">
54 54 <i class="icon-more"></i>
55 55 <div class="menu_items_container hidden">
56 56 <ul class="menu_items">
57 57 <li>
58 58 <a title="${_('Summary')}" href="${h.route_path('repo_summary',repo_name=repo_name)}">
59 59 <span>${_('Summary')}</span>
60 60 </a>
61 61 </li>
62 62 <li>
63 63 <a title="${_('Commits')}" href="${h.route_path('repo_commits',repo_name=repo_name)}">
64 64 <span>${_('Commits')}</span>
65 65 </a>
66 66 </li>
67 67 <li>
68 68 <a title="${_('Files')}" href="${h.route_path('repo_files:default_commit',repo_name=repo_name)}">
69 69 <span>${_('Files')}</span>
70 70 </a>
71 71 </li>
72 72 <li>
73 73 <a title="${_('Fork')}" href="${h.route_path('repo_fork_new',repo_name=repo_name)}">
74 74 <span>${_('Fork')}</span>
75 75 </a>
76 76 </li>
77 77 </ul>
78 78 </div>
79 79 </%def>
80 80
81 81 <%def name="repo_name(name,rtype,rstate,private,archived,fork_of,short_name=False,admin=False)">
82 82 <%
83 83 def get_name(name,short_name=short_name):
84 84 if short_name:
85 85 return name.split('/')[-1]
86 86 else:
87 87 return name
88 88 %>
89 89 <div class="${'repo_state_pending' if rstate == 'repo_state_pending' else ''} truncate">
90 90 ##NAME
91 91 <a href="${h.route_path('edit_repo',repo_name=name) if admin else h.route_path('repo_summary',repo_name=name)}">
92 92
93 93 ##TYPE OF REPO
94 94 %if h.is_hg(rtype):
95 95 <span title="${_('Mercurial repository')}"><i class="icon-hg" style="font-size: 14px;"></i></span>
96 96 %elif h.is_git(rtype):
97 97 <span title="${_('Git repository')}"><i class="icon-git" style="font-size: 14px"></i></span>
98 98 %elif h.is_svn(rtype):
99 99 <span title="${_('Subversion repository')}"><i class="icon-svn" style="font-size: 14px"></i></span>
100 100 %endif
101 101
102 102 ##PRIVATE/PUBLIC
103 103 %if private is True and c.visual.show_private_icon:
104 104 <i class="icon-lock" title="${_('Private repository')}"></i>
105 105 %elif private is False and c.visual.show_public_icon:
106 106 <i class="icon-unlock-alt" title="${_('Public repository')}"></i>
107 107 %else:
108 108 <span></span>
109 109 %endif
110 110 ${get_name(name)}
111 111 </a>
112 112 %if fork_of:
113 113 <a href="${h.route_path('repo_summary',repo_name=fork_of.repo_name)}"><i class="icon-code-fork"></i></a>
114 114 %endif
115 115 %if rstate == 'repo_state_pending':
116 116 <span class="creation_in_progress tooltip" title="${_('This repository is being created in a background task')}">
117 117 (${_('creating...')})
118 118 </span>
119 119 %endif
120 120
121 121 </div>
122 122 </%def>
123 123
124 124 <%def name="repo_desc(description, stylify_metatags)">
125 125 <%
126 126 tags, description = h.extract_metatags(description)
127 127 %>
128 128
129 129 <div class="truncate-wrap">
130 130 % if stylify_metatags:
131 131 % for tag_type, tag in tags:
132 132 ${h.style_metatag(tag_type, tag)|n}
133 133 % endfor
134 134 % endif
135 135 ${description}
136 136 </div>
137 137
138 138 </%def>
139 139
140 140 <%def name="last_change(last_change)">
141 141 ${h.age_component(last_change, time_is_local=True)}
142 142 </%def>
143 143
144 144 <%def name="revision(repo_name, rev, commit_id, author, last_msg, commit_date)">
145 145 <div>
146 146 %if rev >= 0:
147 147 <code><a class="tooltip-hovercard" data-hovercard-alt=${h.tooltip(last_msg)} data-hovercard-url="${h.route_path('hovercard_repo_commit', repo_name=repo_name, commit_id=commit_id)}" href="${h.route_path('repo_commit',repo_name=repo_name,commit_id=commit_id)}">${'r{}:{}'.format(rev,h.short_id(commit_id))}</a></code>
148 148 %else:
149 149 ${_('No commits yet')}
150 150 %endif
151 151 </div>
152 152 </%def>
153 153
154 154 <%def name="rss(name)">
155 155 %if c.rhodecode_user.username != h.DEFAULT_USER:
156 156 <a title="${h.tooltip(_('Subscribe to %s rss feed')% name)}" href="${h.route_path('rss_feed_home', repo_name=name, _query=dict(auth_token=c.rhodecode_user.feed_token))}"><i class="icon-rss-sign"></i></a>
157 157 %else:
158 158 <a title="${h.tooltip(_('Subscribe to %s rss feed')% name)}" href="${h.route_path('rss_feed_home', repo_name=name)}"><i class="icon-rss-sign"></i></a>
159 159 %endif
160 160 </%def>
161 161
162 162 <%def name="atom(name)">
163 163 %if c.rhodecode_user.username != h.DEFAULT_USER:
164 164 <a title="${h.tooltip(_('Subscribe to %s atom feed')% name)}" href="${h.route_path('atom_feed_home', repo_name=name, _query=dict(auth_token=c.rhodecode_user.feed_token))}"><i class="icon-rss-sign"></i></a>
165 165 %else:
166 166 <a title="${h.tooltip(_('Subscribe to %s atom feed')% name)}" href="${h.route_path('atom_feed_home', repo_name=name)}"><i class="icon-rss-sign"></i></a>
167 167 %endif
168 168 </%def>
169 169
170 170 <%def name="repo_actions(repo_name, super_user=True)">
171 171 <div>
172 172 <div class="grid_edit">
173 173 <a href="${h.route_path('edit_repo',repo_name=repo_name)}" title="${_('Edit')}">
174 174 Edit
175 175 </a>
176 176 </div>
177 177 <div class="grid_delete">
178 178 ${h.secure_form(h.route_path('edit_repo_advanced_delete', repo_name=repo_name), request=request)}
179 179 <input class="btn btn-link btn-danger" id="remove_${repo_name}" name="remove_${repo_name}"
180 180 onclick="submitConfirm(event, this, _gettext('Confirm to delete this repository'), _gettext('Delete'), '${repo_name}')"
181 181 type="submit" value="Delete"
182 182 >
183 183 ${h.end_form()}
184 184 </div>
185 185 </div>
186 186 </%def>
187 187
188 188 <%def name="repo_state(repo_state)">
189 189 <div>
190 190 %if repo_state == 'repo_state_pending':
191 191 <div class="tag tag4">${_('Creating')}</div>
192 192 %elif repo_state == 'repo_state_created':
193 193 <div class="tag tag1">${_('Created')}</div>
194 194 %else:
195 195 <div class="tag alert2" title="${h.tooltip(repo_state)}">invalid</div>
196 196 %endif
197 197 </div>
198 198 </%def>
199 199
200 200
201 201 ## REPO GROUP RENDERERS
202 202 <%def name="quick_repo_group_menu(repo_group_name)">
203 203 <i class="icon-more"></i>
204 204 <div class="menu_items_container hidden">
205 205 <ul class="menu_items">
206 206 <li>
207 207 <a href="${h.route_path('repo_group_home', repo_group_name=repo_group_name)}">${_('Summary')}</a>
208 208 </li>
209 209
210 210 </ul>
211 211 </div>
212 212 </%def>
213 213
214 214 <%def name="repo_group_name(repo_group_name, children_groups=None)">
215 215 <div>
216 216 <a href="${h.route_path('repo_group_home', repo_group_name=repo_group_name)}">
217 217 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
218 218 %if children_groups:
219 219 ${h.literal(' &raquo; '.join(children_groups))}
220 220 %else:
221 221 ${repo_group_name}
222 222 %endif
223 223 </a>
224 224 </div>
225 225 </%def>
226 226
227 227 <%def name="repo_group_desc(description, personal, stylify_metatags)">
228 228
229 229 <%
230 230 if stylify_metatags:
231 231 tags, description = h.extract_metatags(description)
232 232 %>
233 233
234 234 <div class="truncate-wrap">
235 235 % if personal:
236 236 <div class="metatag" tag="personal">${_('personal')}</div>
237 237 % endif
238 238
239 239 % if stylify_metatags:
240 240 % for tag_type, tag in tags:
241 241 ${h.style_metatag(tag_type, tag)|n}
242 242 % endfor
243 243 % endif
244 244 ${description}
245 245 </div>
246 246
247 247 </%def>
248 248
249 249 <%def name="repo_group_actions(repo_group_id, repo_group_name, gr_count)">
250 250 <div class="grid_edit">
251 251 <a href="${h.route_path('edit_repo_group',repo_group_name=repo_group_name)}" title="${_('Edit')}">Edit</a>
252 252 </div>
253 253 <div class="grid_delete">
254 254 ${h.secure_form(h.route_path('edit_repo_group_advanced_delete', repo_group_name=repo_group_name), request=request)}
255 255 <input class="btn btn-link btn-danger" id="remove_${repo_group_name}" name="remove_${repo_group_name}"
256 256 onclick="submitConfirm(event, this, _gettext('Confirm to delete this repository group'), _gettext('Delete'), '${_ungettext('`{}` with {} repository','`{}` with {} repositories',gr_count).format(repo_group_name, gr_count)}')"
257 257 type="submit" value="Delete"
258 258 >
259 259 ${h.end_form()}
260 260 </div>
261 261 </%def>
262 262
263 263
264 264 <%def name="user_actions(user_id, username)">
265 265 <div class="grid_edit">
266 266 <a href="${h.route_path('user_edit',user_id=user_id)}" title="${_('Edit')}">
267 267 ${_('Edit')}
268 268 </a>
269 269 </div>
270 270 <div class="grid_delete">
271 271 ${h.secure_form(h.route_path('user_delete', user_id=user_id), request=request)}
272 272 <input class="btn btn-link btn-danger" id="remove_user_${user_id}" name="remove_user_${user_id}"
273 273 onclick="submitConfirm(event, this, _gettext('Confirm to delete this user'), _gettext('Delete'), '${username}')"
274 274 type="submit" value="Delete"
275 275 >
276 276 ${h.end_form()}
277 277 </div>
278 278 </%def>
279 279
280 280 <%def name="user_group_actions(user_group_id, user_group_name)">
281 281 <div class="grid_edit">
282 282 <a href="${h.route_path('edit_user_group', user_group_id=user_group_id)}" title="${_('Edit')}">Edit</a>
283 283 </div>
284 284 <div class="grid_delete">
285 285 ${h.secure_form(h.route_path('user_groups_delete', user_group_id=user_group_id), request=request)}
286 286 <input class="btn btn-link btn-danger" id="remove_group_${user_group_id}" name="remove_group_${user_group_id}"
287 287 onclick="submitConfirm(event, this, _gettext('Confirm to delete this user group'), _gettext('Delete'), '${user_group_name}')"
288 288 type="submit" value="Delete"
289 289 >
290 290 ${h.end_form()}
291 291 </div>
292 292 </%def>
293 293
294 294
295 295 <%def name="user_name(user_id, username)">
296 296 ${h.link_to(h.person(username, 'username_or_name_or_email'), h.route_path('user_edit', user_id=user_id))}
297 297 </%def>
298 298
299 299 <%def name="user_profile(username)">
300 300 ${base.gravatar_with_user(username, 16, tooltip=True)}
301 301 </%def>
302 302
303 303 <%def name="user_group_name(user_group_name)">
304 304 <div>
305 305 <i class="icon-user-group" title="${_('User group')}"></i>
306 306 ${h.link_to_group(user_group_name)}
307 307 </div>
308 308 </%def>
309 309
310 310
311 311 ## GISTS
312 312
313 313 <%def name="gist_gravatar(full_contact)">
314 314 <div class="gist_gravatar">
315 315 ${base.gravatar(full_contact, 30)}
316 316 </div>
317 317 </%def>
318 318
319 319 <%def name="gist_access_id(gist_access_id, full_contact)">
320 320 <div>
321 321 <code>
322 322 <a href="${h.route_path('gist_show', gist_id=gist_access_id)}">${gist_access_id}</a>
323 323 </code>
324 324 </div>
325 325 </%def>
326 326
327 327 <%def name="gist_author(full_contact, created_on, expires)">
328 328 ${base.gravatar_with_user(full_contact, 16, tooltip=True)}
329 329 </%def>
330 330
331 331
332 332 <%def name="gist_created(created_on)">
333 333 <div class="created">
334 334 ${h.age_component(created_on, time_is_local=True)}
335 335 </div>
336 336 </%def>
337 337
338 338 <%def name="gist_expires(expires)">
339 339 <div class="created">
340 340 %if expires == -1:
341 341 ${_('never')}
342 342 %else:
343 343 ${h.age_component(h.time_to_utcdatetime(expires))}
344 344 %endif
345 345 </div>
346 346 </%def>
347 347
348 348 <%def name="gist_type(gist_type)">
349 349 %if gist_type == 'public':
350 350 <span class="tag tag-gist-public disabled">${_('Public Gist')}</span>
351 351 %else:
352 352 <span class="tag tag-gist-private disabled">${_('Private Gist')}</span>
353 353 %endif
354 354 </%def>
355 355
356 356 <%def name="gist_description(gist_description)">
357 357 ${gist_description}
358 358 </%def>
359 359
360 360
361 361 ## PULL REQUESTS GRID RENDERERS
362 362
363 363 <%def name="pullrequest_target_repo(repo_name)">
364 364 <div class="truncate">
365 365 ${h.link_to(repo_name,h.route_path('repo_summary',repo_name=repo_name))}
366 366 </div>
367 367 </%def>
368 368
369 369 <%def name="pullrequest_status(status)">
370 370 <i class="icon-circle review-status-${status}"></i>
371 371 </%def>
372 372
373 373 <%def name="pullrequest_title(title, description)">
374 374 ${title}
375 375 </%def>
376 376
377 377 <%def name="pullrequest_comments(comments_nr)">
378 378 <i class="icon-comment"></i> ${comments_nr}
379 379 </%def>
380 380
381 381 <%def name="pullrequest_name(pull_request_id, state, is_wip, target_repo_name, short=False)">
382 382 <code>
383 383 <a href="${h.route_path('pullrequest_show',repo_name=target_repo_name,pull_request_id=pull_request_id)}">
384 384 % if short:
385 385 !${pull_request_id}
386 386 % else:
387 387 ${_('Pull request !{}').format(pull_request_id)}
388 388 % endif
389 389 </a>
390 390 </code>
391 391 % if state not in ['created']:
392 392 <span class="tag tag-merge-state-${state} tooltip" title="Pull request state is changing">${state}</span>
393 393 % endif
394 394
395 395 % if is_wip:
396 396 <span class="tag tooltip" title="${_('Work in progress')}">wip</span>
397 397 % endif
398 398 </%def>
399 399
400 400 <%def name="pullrequest_updated_on(updated_on, pr_version=None)">
401 401 % if pr_version:
402 402 <code>v${pr_version}</code>
403 403 % endif
404 404 ${h.age_component(h.time_to_utcdatetime(updated_on))}
405 405 </%def>
406 406
407 407 <%def name="pullrequest_author(full_contact)">
408 408 ${base.gravatar_with_user(full_contact, 16, tooltip=True)}
409 409 </%def>
410 410
411 411
412 412 ## ARTIFACT RENDERERS
413 413 <%def name="repo_artifact_name(repo_name, file_uid, artifact_display_name)">
414 414 <a href="${h.route_path('repo_artifacts_get', repo_name=repo_name, uid=file_uid)}">
415 415 ${artifact_display_name or '_EMPTY_NAME_'}
416 416 </a>
417 417 </%def>
418 418
419 <%def name="repo_artifact_admin_name(file_uid, artifact_display_name)">
420 <a href="${h.route_path('admin_artifacts_show_info', uid=file_uid)}">
421 ${(artifact_display_name or '_EMPTY_NAME_')}
422 </a>
423 </%def>
424
419 425 <%def name="repo_artifact_uid(repo_name, file_uid)">
420 426 <code>${h.shorter(file_uid, size=24, prefix=True)}</code>
421 427 </%def>
422 428
423 429 <%def name="repo_artifact_sha256(artifact_sha256)">
424 430 <div class="code">${h.shorter(artifact_sha256, 12)}</div>
425 431 </%def>
426 432
427 433 <%def name="repo_artifact_actions(repo_name, file_store_id, file_uid)">
428 434 ## <div class="grid_edit">
429 435 ## <a href="#Edit" title="${_('Edit')}">${_('Edit')}</a>
430 436 ## </div>
431 437 <div class="grid_edit">
432 438 <a href="${h.route_path('repo_artifacts_info', repo_name=repo_name, uid=file_store_id)}" title="${_('Info')}">${_('Info')}</a>
433 439 </div>
434 440 % if h.HasRepoPermissionAny('repository.admin')(c.repo_name):
435 441 <div class="grid_delete">
436 442 ${h.secure_form(h.route_path('repo_artifacts_delete', repo_name=repo_name, uid=file_store_id), request=request)}
437 443 <input class="btn btn-link btn-danger" id="remove_artifact_${file_store_id}" name="remove_artifact_${file_store_id}"
438 444 onclick="submitConfirm(event, this, _gettext('Confirm to delete this artifact'), _gettext('Delete'), '${file_uid}')"
439 445 type="submit" value="${_('Delete')}"
440 446 >
441 447 ${h.end_form()}
442 448 </div>
443 449 % endif
444 450 </%def>
445 451
452
446 453 <%def name="markup_form(form_id, form_text='', help_text=None)">
447 454
448 455 <div class="markup-form">
449 456 <div class="markup-form-area">
450 457 <div class="markup-form-area-header">
451 458 <ul class="nav-links clearfix">
452 459 <li class="active">
453 460 <a href="#edit-text" tabindex="-1" id="edit-btn_${form_id}">${_('Write')}</a>
454 461 </li>
455 462 <li class="">
456 463 <a href="#preview-text" tabindex="-1" id="preview-btn_${form_id}">${_('Preview')}</a>
457 464 </li>
458 465 </ul>
459 466 </div>
460 467
461 468 <div class="markup-form-area-write" style="display: block;">
462 469 <div id="edit-container_${form_id}" style="margin-top: -1px">
463 470 <textarea id="${form_id}" name="${form_id}" class="comment-block-ta ac-input">${form_text if form_text else ''}</textarea>
464 471 </div>
465 472 <div id="preview-container_${form_id}" class="clearfix" style="display: none;">
466 473 <div id="preview-box_${form_id}" class="preview-box"></div>
467 474 </div>
468 475 </div>
469 476
470 477 <div class="markup-form-area-footer">
471 478 <div class="toolbar">
472 479 <div class="toolbar-text">
473 480 ${(_('Parsed using %s syntax') % (
474 481 ('<a href="%s">%s</a>' % (h.route_url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())),
475 482 )
476 483 )|n}
477 484 </div>
478 485 </div>
479 486 </div>
480 487 </div>
481 488
482 489 <div class="markup-form-footer">
483 490 % if help_text:
484 491 <span class="help-block">${help_text}</span>
485 492 % endif
486 493 </div>
487 494 </div>
488 495 <script type="text/javascript">
489 496 new MarkupForm('${form_id}');
490 497 </script>
491 498
492 499 </%def>
General Comments 0
You need to be logged in to leave comments. Login now