##// END OF EJS Templates
files: updated based on new design
marcink -
r3706:9aa2b595 new-ui
parent child Browse files
Show More
@@ -1,1393 +1,1392 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2011-2019 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 itertools
22 22 import logging
23 23 import os
24 24 import shutil
25 25 import tempfile
26 26 import collections
27 27 import urllib
28 28
29 29 from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound
30 30 from pyramid.view import view_config
31 31 from pyramid.renderers import render
32 32 from pyramid.response import Response
33 33
34 34 import rhodecode
35 35 from rhodecode.apps._base import RepoAppView
36 36
37 37
38 38 from rhodecode.lib import diffs, helpers as h, rc_cache
39 39 from rhodecode.lib import audit_logger
40 40 from rhodecode.lib.view_utils import parse_path_ref
41 41 from rhodecode.lib.exceptions import NonRelativePathError
42 42 from rhodecode.lib.codeblocks import (
43 43 filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
44 44 from rhodecode.lib.utils2 import (
45 45 convert_line_endings, detect_mode, safe_str, str2bool, safe_int)
46 46 from rhodecode.lib.auth import (
47 47 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
48 48 from rhodecode.lib.vcs import path as vcspath
49 49 from rhodecode.lib.vcs.backends.base import EmptyCommit
50 50 from rhodecode.lib.vcs.conf import settings
51 51 from rhodecode.lib.vcs.nodes import FileNode
52 52 from rhodecode.lib.vcs.exceptions import (
53 53 RepositoryError, CommitDoesNotExistError, EmptyRepositoryError,
54 54 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,
55 55 NodeDoesNotExistError, CommitError, NodeError)
56 56
57 57 from rhodecode.model.scm import ScmModel
58 58 from rhodecode.model.db import Repository
59 59
60 60 log = logging.getLogger(__name__)
61 61
62 62
63 63 class RepoFilesView(RepoAppView):
64 64
65 65 @staticmethod
66 66 def adjust_file_path_for_svn(f_path, repo):
67 67 """
68 68 Computes the relative path of `f_path`.
69 69
70 70 This is mainly based on prefix matching of the recognized tags and
71 71 branches in the underlying repository.
72 72 """
73 73 tags_and_branches = itertools.chain(
74 74 repo.branches.iterkeys(),
75 75 repo.tags.iterkeys())
76 76 tags_and_branches = sorted(tags_and_branches, key=len, reverse=True)
77 77
78 78 for name in tags_and_branches:
79 79 if f_path.startswith('{}/'.format(name)):
80 80 f_path = vcspath.relpath(f_path, name)
81 81 break
82 82 return f_path
83 83
84 84 def load_default_context(self):
85 85 c = self._get_local_tmpl_context(include_app_defaults=True)
86 86 c.rhodecode_repo = self.rhodecode_vcs_repo
87 87 c.enable_downloads = self.db_repo.enable_downloads
88 88 return c
89 89
90 90 def _ensure_not_locked(self):
91 91 _ = self.request.translate
92 92
93 93 repo = self.db_repo
94 94 if repo.enable_locking and repo.locked[0]:
95 95 h.flash(_('This repository has been locked by %s on %s')
96 96 % (h.person_by_id(repo.locked[0]),
97 97 h.format_date(h.time_to_datetime(repo.locked[1]))),
98 98 'warning')
99 99 files_url = h.route_path(
100 100 'repo_files:default_path',
101 101 repo_name=self.db_repo_name, commit_id='tip')
102 102 raise HTTPFound(files_url)
103 103
104 104 def check_branch_permission(self, branch_name):
105 105 _ = self.request.translate
106 106
107 107 rule, branch_perm = self._rhodecode_user.get_rule_and_branch_permission(
108 108 self.db_repo_name, branch_name)
109 109 if branch_perm and branch_perm not in ['branch.push', 'branch.push_force']:
110 110 h.flash(
111 111 _('Branch `{}` changes forbidden by rule {}.').format(branch_name, rule),
112 112 'warning')
113 113 files_url = h.route_path(
114 114 'repo_files:default_path',
115 115 repo_name=self.db_repo_name, commit_id='tip')
116 116 raise HTTPFound(files_url)
117 117
118 118 def _get_commit_and_path(self):
119 119 default_commit_id = self.db_repo.landing_rev[1]
120 120 default_f_path = '/'
121 121
122 122 commit_id = self.request.matchdict.get(
123 123 'commit_id', default_commit_id)
124 124 f_path = self._get_f_path(self.request.matchdict, default_f_path)
125 125 return commit_id, f_path
126 126
127 127 def _get_default_encoding(self, c):
128 128 enc_list = getattr(c, 'default_encodings', [])
129 129 return enc_list[0] if enc_list else 'UTF-8'
130 130
131 131 def _get_commit_or_redirect(self, commit_id, redirect_after=True):
132 132 """
133 133 This is a safe way to get commit. If an error occurs it redirects to
134 134 tip with proper message
135 135
136 136 :param commit_id: id of commit to fetch
137 137 :param redirect_after: toggle redirection
138 138 """
139 139 _ = self.request.translate
140 140
141 141 try:
142 142 return self.rhodecode_vcs_repo.get_commit(commit_id)
143 143 except EmptyRepositoryError:
144 144 if not redirect_after:
145 145 return None
146 146
147 147 _url = h.route_path(
148 148 'repo_files_add_file',
149 149 repo_name=self.db_repo_name, commit_id=0, f_path='',
150 150 _anchor='edit')
151 151
152 152 if h.HasRepoPermissionAny(
153 153 'repository.write', 'repository.admin')(self.db_repo_name):
154 154 add_new = h.link_to(
155 155 _('Click here to add a new file.'), _url, class_="alert-link")
156 156 else:
157 157 add_new = ""
158 158
159 159 h.flash(h.literal(
160 160 _('There are no files yet. %s') % add_new), category='warning')
161 161 raise HTTPFound(
162 162 h.route_path('repo_summary', repo_name=self.db_repo_name))
163 163
164 164 except (CommitDoesNotExistError, LookupError):
165 165 msg = _('No such commit exists for this repository')
166 166 h.flash(msg, category='error')
167 167 raise HTTPNotFound()
168 168 except RepositoryError as e:
169 169 h.flash(safe_str(h.escape(e)), category='error')
170 170 raise HTTPNotFound()
171 171
172 172 def _get_filenode_or_redirect(self, commit_obj, path):
173 173 """
174 174 Returns file_node, if error occurs or given path is directory,
175 175 it'll redirect to top level path
176 176 """
177 177 _ = self.request.translate
178 178
179 179 try:
180 180 file_node = commit_obj.get_node(path)
181 181 if file_node.is_dir():
182 182 raise RepositoryError('The given path is a directory')
183 183 except CommitDoesNotExistError:
184 184 log.exception('No such commit exists for this repository')
185 185 h.flash(_('No such commit exists for this repository'), category='error')
186 186 raise HTTPNotFound()
187 187 except RepositoryError as e:
188 188 log.warning('Repository error while fetching '
189 189 'filenode `%s`. Err:%s', path, e)
190 190 h.flash(safe_str(h.escape(e)), category='error')
191 191 raise HTTPNotFound()
192 192
193 193 return file_node
194 194
195 195 def _is_valid_head(self, commit_id, repo):
196 196 branch_name = sha_commit_id = ''
197 197 is_head = False
198 198
199 199 if h.is_svn(repo) and not repo.is_empty():
200 200 # Note: Subversion only has one head.
201 201 if commit_id == repo.get_commit(commit_idx=-1).raw_id:
202 202 is_head = True
203 203 return branch_name, sha_commit_id, is_head
204 204
205 205 for _branch_name, branch_commit_id in repo.branches.items():
206 206 # simple case we pass in branch name, it's a HEAD
207 207 if commit_id == _branch_name:
208 208 is_head = True
209 209 branch_name = _branch_name
210 210 sha_commit_id = branch_commit_id
211 211 break
212 212 # case when we pass in full sha commit_id, which is a head
213 213 elif commit_id == branch_commit_id:
214 214 is_head = True
215 215 branch_name = _branch_name
216 216 sha_commit_id = branch_commit_id
217 217 break
218 218
219 219 # checked branches, means we only need to try to get the branch/commit_sha
220 220 if not repo.is_empty:
221 221 commit = repo.get_commit(commit_id=commit_id)
222 222 if commit:
223 223 branch_name = commit.branch
224 224 sha_commit_id = commit.raw_id
225 225
226 226 return branch_name, sha_commit_id, is_head
227 227
228 228 def _get_tree_at_commit(self, c, commit_id, f_path, full_load=False):
229 229
230 230 repo_id = self.db_repo.repo_id
231 231 force_recache = self.get_recache_flag()
232 232
233 233 cache_seconds = safe_int(
234 234 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
235 235 cache_on = not force_recache and cache_seconds > 0
236 236 log.debug(
237 237 'Computing FILE TREE for repo_id %s commit_id `%s` and path `%s`'
238 238 'with caching: %s[TTL: %ss]' % (
239 239 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
240 240
241 241 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
242 242 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
243 243
244 244 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
245 245 condition=cache_on)
246 246 def compute_file_tree(repo_id, commit_id, f_path, full_load):
247 247 log.debug('Generating cached file tree for repo_id: %s, %s, %s',
248 248 repo_id, commit_id, f_path)
249 249
250 250 c.full_load = full_load
251 251 return render(
252 252 'rhodecode:templates/files/files_browser_tree.mako',
253 253 self._get_template_context(c), self.request)
254 254
255 255 return compute_file_tree(self.db_repo.repo_id, commit_id, f_path, full_load)
256 256
257 257 def _get_archive_spec(self, fname):
258 258 log.debug('Detecting archive spec for: `%s`', fname)
259 259
260 260 fileformat = None
261 261 ext = None
262 262 content_type = None
263 263 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
264 264 content_type, extension = ext_data
265 265
266 266 if fname.endswith(extension):
267 267 fileformat = a_type
268 268 log.debug('archive is of type: %s', fileformat)
269 269 ext = extension
270 270 break
271 271
272 272 if not fileformat:
273 273 raise ValueError()
274 274
275 275 # left over part of whole fname is the commit
276 276 commit_id = fname[:-len(ext)]
277 277
278 278 return commit_id, ext, fileformat, content_type
279 279
280 280 @LoginRequired()
281 281 @HasRepoPermissionAnyDecorator(
282 282 'repository.read', 'repository.write', 'repository.admin')
283 283 @view_config(
284 284 route_name='repo_archivefile', request_method='GET',
285 285 renderer=None)
286 286 def repo_archivefile(self):
287 287 # archive cache config
288 288 from rhodecode import CONFIG
289 289 _ = self.request.translate
290 290 self.load_default_context()
291 291
292 292 fname = self.request.matchdict['fname']
293 293 subrepos = self.request.GET.get('subrepos') == 'true'
294 294
295 295 if not self.db_repo.enable_downloads:
296 296 return Response(_('Downloads disabled'))
297 297
298 298 try:
299 299 commit_id, ext, fileformat, content_type = \
300 300 self._get_archive_spec(fname)
301 301 except ValueError:
302 302 return Response(_('Unknown archive type for: `{}`').format(
303 303 h.escape(fname)))
304 304
305 305 try:
306 306 commit = self.rhodecode_vcs_repo.get_commit(commit_id)
307 307 except CommitDoesNotExistError:
308 308 return Response(_('Unknown commit_id {}').format(
309 309 h.escape(commit_id)))
310 310 except EmptyRepositoryError:
311 311 return Response(_('Empty repository'))
312 312
313 313 archive_name = '%s-%s%s%s' % (
314 314 safe_str(self.db_repo_name.replace('/', '_')),
315 315 '-sub' if subrepos else '',
316 316 safe_str(commit.short_id), ext)
317 317
318 318 use_cached_archive = False
319 319 archive_cache_enabled = CONFIG.get(
320 320 'archive_cache_dir') and not self.request.GET.get('no_cache')
321 321 cached_archive_path = None
322 322
323 323 if archive_cache_enabled:
324 324 # check if we it's ok to write
325 325 if not os.path.isdir(CONFIG['archive_cache_dir']):
326 326 os.makedirs(CONFIG['archive_cache_dir'])
327 327 cached_archive_path = os.path.join(
328 328 CONFIG['archive_cache_dir'], archive_name)
329 329 if os.path.isfile(cached_archive_path):
330 330 log.debug('Found cached archive in %s', cached_archive_path)
331 331 fd, archive = None, cached_archive_path
332 332 use_cached_archive = True
333 333 else:
334 334 log.debug('Archive %s is not yet cached', archive_name)
335 335
336 336 if not use_cached_archive:
337 337 # generate new archive
338 338 fd, archive = tempfile.mkstemp()
339 339 log.debug('Creating new temp archive in %s', archive)
340 340 try:
341 341 commit.archive_repo(archive, kind=fileformat, subrepos=subrepos)
342 342 except ImproperArchiveTypeError:
343 343 return _('Unknown archive type')
344 344 if archive_cache_enabled:
345 345 # if we generated the archive and we have cache enabled
346 346 # let's use this for future
347 347 log.debug('Storing new archive in %s', cached_archive_path)
348 348 shutil.move(archive, cached_archive_path)
349 349 archive = cached_archive_path
350 350
351 351 # store download action
352 352 audit_logger.store_web(
353 353 'repo.archive.download', action_data={
354 354 'user_agent': self.request.user_agent,
355 355 'archive_name': archive_name,
356 356 'archive_spec': fname,
357 357 'archive_cached': use_cached_archive},
358 358 user=self._rhodecode_user,
359 359 repo=self.db_repo,
360 360 commit=True
361 361 )
362 362
363 363 def get_chunked_archive(archive_path):
364 364 with open(archive_path, 'rb') as stream:
365 365 while True:
366 366 data = stream.read(16 * 1024)
367 367 if not data:
368 368 if fd: # fd means we used temporary file
369 369 os.close(fd)
370 370 if not archive_cache_enabled:
371 371 log.debug('Destroying temp archive %s', archive_path)
372 372 os.remove(archive_path)
373 373 break
374 374 yield data
375 375
376 376 response = Response(app_iter=get_chunked_archive(archive))
377 377 response.content_disposition = str(
378 378 'attachment; filename=%s' % archive_name)
379 379 response.content_type = str(content_type)
380 380
381 381 return response
382 382
383 383 def _get_file_node(self, commit_id, f_path):
384 384 if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]:
385 385 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
386 386 try:
387 387 node = commit.get_node(f_path)
388 388 if node.is_dir():
389 389 raise NodeError('%s path is a %s not a file'
390 390 % (node, type(node)))
391 391 except NodeDoesNotExistError:
392 392 commit = EmptyCommit(
393 393 commit_id=commit_id,
394 394 idx=commit.idx,
395 395 repo=commit.repository,
396 396 alias=commit.repository.alias,
397 397 message=commit.message,
398 398 author=commit.author,
399 399 date=commit.date)
400 400 node = FileNode(f_path, '', commit=commit)
401 401 else:
402 402 commit = EmptyCommit(
403 403 repo=self.rhodecode_vcs_repo,
404 404 alias=self.rhodecode_vcs_repo.alias)
405 405 node = FileNode(f_path, '', commit=commit)
406 406 return node
407 407
408 408 @LoginRequired()
409 409 @HasRepoPermissionAnyDecorator(
410 410 'repository.read', 'repository.write', 'repository.admin')
411 411 @view_config(
412 412 route_name='repo_files_diff', request_method='GET',
413 413 renderer=None)
414 414 def repo_files_diff(self):
415 415 c = self.load_default_context()
416 416 f_path = self._get_f_path(self.request.matchdict)
417 417 diff1 = self.request.GET.get('diff1', '')
418 418 diff2 = self.request.GET.get('diff2', '')
419 419
420 420 path1, diff1 = parse_path_ref(diff1, default_path=f_path)
421 421
422 422 ignore_whitespace = str2bool(self.request.GET.get('ignorews'))
423 423 line_context = self.request.GET.get('context', 3)
424 424
425 425 if not any((diff1, diff2)):
426 426 h.flash(
427 427 'Need query parameter "diff1" or "diff2" to generate a diff.',
428 428 category='error')
429 429 raise HTTPBadRequest()
430 430
431 431 c.action = self.request.GET.get('diff')
432 432 if c.action not in ['download', 'raw']:
433 433 compare_url = h.route_path(
434 434 'repo_compare',
435 435 repo_name=self.db_repo_name,
436 436 source_ref_type='rev',
437 437 source_ref=diff1,
438 438 target_repo=self.db_repo_name,
439 439 target_ref_type='rev',
440 440 target_ref=diff2,
441 441 _query=dict(f_path=f_path))
442 442 # redirect to new view if we render diff
443 443 raise HTTPFound(compare_url)
444 444
445 445 try:
446 446 node1 = self._get_file_node(diff1, path1)
447 447 node2 = self._get_file_node(diff2, f_path)
448 448 except (RepositoryError, NodeError):
449 449 log.exception("Exception while trying to get node from repository")
450 450 raise HTTPFound(
451 451 h.route_path('repo_files', repo_name=self.db_repo_name,
452 452 commit_id='tip', f_path=f_path))
453 453
454 454 if all(isinstance(node.commit, EmptyCommit)
455 455 for node in (node1, node2)):
456 456 raise HTTPNotFound()
457 457
458 458 c.commit_1 = node1.commit
459 459 c.commit_2 = node2.commit
460 460
461 461 if c.action == 'download':
462 462 _diff = diffs.get_gitdiff(node1, node2,
463 463 ignore_whitespace=ignore_whitespace,
464 464 context=line_context)
465 465 diff = diffs.DiffProcessor(_diff, format='gitdiff')
466 466
467 467 response = Response(self.path_filter.get_raw_patch(diff))
468 468 response.content_type = 'text/plain'
469 469 response.content_disposition = (
470 470 'attachment; filename=%s_%s_vs_%s.diff' % (f_path, diff1, diff2)
471 471 )
472 472 charset = self._get_default_encoding(c)
473 473 if charset:
474 474 response.charset = charset
475 475 return response
476 476
477 477 elif c.action == 'raw':
478 478 _diff = diffs.get_gitdiff(node1, node2,
479 479 ignore_whitespace=ignore_whitespace,
480 480 context=line_context)
481 481 diff = diffs.DiffProcessor(_diff, format='gitdiff')
482 482
483 483 response = Response(self.path_filter.get_raw_patch(diff))
484 484 response.content_type = 'text/plain'
485 485 charset = self._get_default_encoding(c)
486 486 if charset:
487 487 response.charset = charset
488 488 return response
489 489
490 490 # in case we ever end up here
491 491 raise HTTPNotFound()
492 492
493 493 @LoginRequired()
494 494 @HasRepoPermissionAnyDecorator(
495 495 'repository.read', 'repository.write', 'repository.admin')
496 496 @view_config(
497 497 route_name='repo_files_diff_2way_redirect', request_method='GET',
498 498 renderer=None)
499 499 def repo_files_diff_2way_redirect(self):
500 500 """
501 501 Kept only to make OLD links work
502 502 """
503 503 f_path = self._get_f_path_unchecked(self.request.matchdict)
504 504 diff1 = self.request.GET.get('diff1', '')
505 505 diff2 = self.request.GET.get('diff2', '')
506 506
507 507 if not any((diff1, diff2)):
508 508 h.flash(
509 509 'Need query parameter "diff1" or "diff2" to generate a diff.',
510 510 category='error')
511 511 raise HTTPBadRequest()
512 512
513 513 compare_url = h.route_path(
514 514 'repo_compare',
515 515 repo_name=self.db_repo_name,
516 516 source_ref_type='rev',
517 517 source_ref=diff1,
518 518 target_ref_type='rev',
519 519 target_ref=diff2,
520 520 _query=dict(f_path=f_path, diffmode='sideside',
521 521 target_repo=self.db_repo_name,))
522 522 raise HTTPFound(compare_url)
523 523
524 524 @LoginRequired()
525 525 @HasRepoPermissionAnyDecorator(
526 526 'repository.read', 'repository.write', 'repository.admin')
527 527 @view_config(
528 528 route_name='repo_files', request_method='GET',
529 529 renderer=None)
530 530 @view_config(
531 531 route_name='repo_files:default_path', request_method='GET',
532 532 renderer=None)
533 533 @view_config(
534 534 route_name='repo_files:default_commit', request_method='GET',
535 535 renderer=None)
536 536 @view_config(
537 537 route_name='repo_files:rendered', request_method='GET',
538 538 renderer=None)
539 539 @view_config(
540 540 route_name='repo_files:annotated', request_method='GET',
541 541 renderer=None)
542 542 def repo_files(self):
543 543 c = self.load_default_context()
544 544
545 545 view_name = getattr(self.request.matched_route, 'name', None)
546 546
547 547 c.annotate = view_name == 'repo_files:annotated'
548 548 # default is false, but .rst/.md files later are auto rendered, we can
549 549 # overwrite auto rendering by setting this GET flag
550 550 c.renderer = view_name == 'repo_files:rendered' or \
551 551 not self.request.GET.get('no-render', False)
552 552
553 553 # redirect to given commit_id from form if given
554 554 get_commit_id = self.request.GET.get('at_rev', None)
555 555 if get_commit_id:
556 556 self._get_commit_or_redirect(get_commit_id)
557 557
558 558 commit_id, f_path = self._get_commit_and_path()
559 559 c.commit = self._get_commit_or_redirect(commit_id)
560 560 c.branch = self.request.GET.get('branch', None)
561 561 c.f_path = f_path
562 562
563 563 # prev link
564 564 try:
565 565 prev_commit = c.commit.prev(c.branch)
566 566 c.prev_commit = prev_commit
567 567 c.url_prev = h.route_path(
568 568 'repo_files', repo_name=self.db_repo_name,
569 569 commit_id=prev_commit.raw_id, f_path=f_path)
570 570 if c.branch:
571 571 c.url_prev += '?branch=%s' % c.branch
572 572 except (CommitDoesNotExistError, VCSError):
573 573 c.url_prev = '#'
574 574 c.prev_commit = EmptyCommit()
575 575
576 576 # next link
577 577 try:
578 578 next_commit = c.commit.next(c.branch)
579 579 c.next_commit = next_commit
580 580 c.url_next = h.route_path(
581 581 'repo_files', repo_name=self.db_repo_name,
582 582 commit_id=next_commit.raw_id, f_path=f_path)
583 583 if c.branch:
584 584 c.url_next += '?branch=%s' % c.branch
585 585 except (CommitDoesNotExistError, VCSError):
586 586 c.url_next = '#'
587 587 c.next_commit = EmptyCommit()
588 588
589 589 # files or dirs
590 590 try:
591 591 c.file = c.commit.get_node(f_path)
592 592 c.file_author = True
593 593 c.file_tree = ''
594 594
595 595 # load file content
596 596 if c.file.is_file():
597 597 c.lf_node = c.file.get_largefile_node()
598 598
599 599 c.file_source_page = 'true'
600 600 c.file_last_commit = c.file.last_commit
601 601 if c.file.size < c.visual.cut_off_limit_diff:
602 602 if c.annotate: # annotation has precedence over renderer
603 603 c.annotated_lines = filenode_as_annotated_lines_tokens(
604 604 c.file
605 605 )
606 606 else:
607 607 c.renderer = (
608 608 c.renderer and h.renderer_from_filename(c.file.path)
609 609 )
610 610 if not c.renderer:
611 611 c.lines = filenode_as_lines_tokens(c.file)
612 612
613 613 _branch_name, _sha_commit_id, is_head = self._is_valid_head(
614 614 commit_id, self.rhodecode_vcs_repo)
615 615 c.on_branch_head = is_head
616 616
617 617 branch = c.commit.branch if (
618 618 c.commit.branch and '/' not in c.commit.branch) else None
619 619 c.branch_or_raw_id = branch or c.commit.raw_id
620 620 c.branch_name = c.commit.branch or h.short_id(c.commit.raw_id)
621 621
622 622 author = c.file_last_commit.author
623 623 c.authors = [[
624 624 h.email(author),
625 625 h.person(author, 'username_or_name_or_email'),
626 626 1
627 627 ]]
628 628
629 629 else: # load tree content at path
630 630 c.file_source_page = 'false'
631 631 c.authors = []
632 632 # this loads a simple tree without metadata to speed things up
633 633 # later via ajax we call repo_nodetree_full and fetch whole
634 634 c.file_tree = self._get_tree_at_commit(c, c.commit.raw_id, f_path)
635 635
636 636 except RepositoryError as e:
637 637 h.flash(safe_str(h.escape(e)), category='error')
638 638 raise HTTPNotFound()
639 639
640 640 if self.request.environ.get('HTTP_X_PJAX'):
641 641 html = render('rhodecode:templates/files/files_pjax.mako',
642 642 self._get_template_context(c), self.request)
643 643 else:
644 644 html = render('rhodecode:templates/files/files.mako',
645 645 self._get_template_context(c), self.request)
646 646 return Response(html)
647 647
648 648 @HasRepoPermissionAnyDecorator(
649 649 'repository.read', 'repository.write', 'repository.admin')
650 650 @view_config(
651 651 route_name='repo_files:annotated_previous', request_method='GET',
652 652 renderer=None)
653 653 def repo_files_annotated_previous(self):
654 654 self.load_default_context()
655 655
656 656 commit_id, f_path = self._get_commit_and_path()
657 657 commit = self._get_commit_or_redirect(commit_id)
658 658 prev_commit_id = commit.raw_id
659 659 line_anchor = self.request.GET.get('line_anchor')
660 660 is_file = False
661 661 try:
662 662 _file = commit.get_node(f_path)
663 663 is_file = _file.is_file()
664 664 except (NodeDoesNotExistError, CommitDoesNotExistError, VCSError):
665 665 pass
666 666
667 667 if is_file:
668 668 history = commit.get_path_history(f_path)
669 669 prev_commit_id = history[1].raw_id \
670 670 if len(history) > 1 else prev_commit_id
671 671 prev_url = h.route_path(
672 672 'repo_files:annotated', repo_name=self.db_repo_name,
673 673 commit_id=prev_commit_id, f_path=f_path,
674 674 _anchor='L{}'.format(line_anchor))
675 675
676 676 raise HTTPFound(prev_url)
677 677
678 678 @LoginRequired()
679 679 @HasRepoPermissionAnyDecorator(
680 680 'repository.read', 'repository.write', 'repository.admin')
681 681 @view_config(
682 682 route_name='repo_nodetree_full', request_method='GET',
683 683 renderer=None, xhr=True)
684 684 @view_config(
685 685 route_name='repo_nodetree_full:default_path', request_method='GET',
686 686 renderer=None, xhr=True)
687 687 def repo_nodetree_full(self):
688 688 """
689 689 Returns rendered html of file tree that contains commit date,
690 690 author, commit_id for the specified combination of
691 691 repo, commit_id and file path
692 692 """
693 693 c = self.load_default_context()
694 694
695 695 commit_id, f_path = self._get_commit_and_path()
696 696 commit = self._get_commit_or_redirect(commit_id)
697 697 try:
698 698 dir_node = commit.get_node(f_path)
699 699 except RepositoryError as e:
700 700 return Response('error: {}'.format(h.escape(safe_str(e))))
701 701
702 702 if dir_node.is_file():
703 703 return Response('')
704 704
705 705 c.file = dir_node
706 706 c.commit = commit
707 707
708 708 html = self._get_tree_at_commit(
709 709 c, commit.raw_id, dir_node.path, full_load=True)
710 710
711 711 return Response(html)
712 712
713 713 def _get_attachement_headers(self, f_path):
714 714 f_name = safe_str(f_path.split(Repository.NAME_SEP)[-1])
715 715 safe_path = f_name.replace('"', '\\"')
716 716 encoded_path = urllib.quote(f_name)
717 717
718 718 return "attachment; " \
719 719 "filename=\"{}\"; " \
720 720 "filename*=UTF-8\'\'{}".format(safe_path, encoded_path)
721 721
722 722 @LoginRequired()
723 723 @HasRepoPermissionAnyDecorator(
724 724 'repository.read', 'repository.write', 'repository.admin')
725 725 @view_config(
726 726 route_name='repo_file_raw', request_method='GET',
727 727 renderer=None)
728 728 def repo_file_raw(self):
729 729 """
730 730 Action for show as raw, some mimetypes are "rendered",
731 731 those include images, icons.
732 732 """
733 733 c = self.load_default_context()
734 734
735 735 commit_id, f_path = self._get_commit_and_path()
736 736 commit = self._get_commit_or_redirect(commit_id)
737 737 file_node = self._get_filenode_or_redirect(commit, f_path)
738 738
739 739 raw_mimetype_mapping = {
740 740 # map original mimetype to a mimetype used for "show as raw"
741 741 # you can also provide a content-disposition to override the
742 742 # default "attachment" disposition.
743 743 # orig_type: (new_type, new_dispo)
744 744
745 745 # show images inline:
746 746 # Do not re-add SVG: it is unsafe and permits XSS attacks. One can
747 747 # for example render an SVG with javascript inside or even render
748 748 # HTML.
749 749 'image/x-icon': ('image/x-icon', 'inline'),
750 750 'image/png': ('image/png', 'inline'),
751 751 'image/gif': ('image/gif', 'inline'),
752 752 'image/jpeg': ('image/jpeg', 'inline'),
753 753 'application/pdf': ('application/pdf', 'inline'),
754 754 }
755 755
756 756 mimetype = file_node.mimetype
757 757 try:
758 758 mimetype, disposition = raw_mimetype_mapping[mimetype]
759 759 except KeyError:
760 760 # we don't know anything special about this, handle it safely
761 761 if file_node.is_binary:
762 762 # do same as download raw for binary files
763 763 mimetype, disposition = 'application/octet-stream', 'attachment'
764 764 else:
765 765 # do not just use the original mimetype, but force text/plain,
766 766 # otherwise it would serve text/html and that might be unsafe.
767 767 # Note: underlying vcs library fakes text/plain mimetype if the
768 768 # mimetype can not be determined and it thinks it is not
769 769 # binary.This might lead to erroneous text display in some
770 770 # cases, but helps in other cases, like with text files
771 771 # without extension.
772 772 mimetype, disposition = 'text/plain', 'inline'
773 773
774 774 if disposition == 'attachment':
775 775 disposition = self._get_attachement_headers(f_path)
776 776
777 777 def stream_node():
778 778 yield file_node.raw_bytes
779 779
780 780 response = Response(app_iter=stream_node())
781 781 response.content_disposition = disposition
782 782 response.content_type = mimetype
783 783
784 784 charset = self._get_default_encoding(c)
785 785 if charset:
786 786 response.charset = charset
787 787
788 788 return response
789 789
790 790 @LoginRequired()
791 791 @HasRepoPermissionAnyDecorator(
792 792 'repository.read', 'repository.write', 'repository.admin')
793 793 @view_config(
794 794 route_name='repo_file_download', request_method='GET',
795 795 renderer=None)
796 796 @view_config(
797 797 route_name='repo_file_download:legacy', request_method='GET',
798 798 renderer=None)
799 799 def repo_file_download(self):
800 800 c = self.load_default_context()
801 801
802 802 commit_id, f_path = self._get_commit_and_path()
803 803 commit = self._get_commit_or_redirect(commit_id)
804 804 file_node = self._get_filenode_or_redirect(commit, f_path)
805 805
806 806 if self.request.GET.get('lf'):
807 807 # only if lf get flag is passed, we download this file
808 808 # as LFS/Largefile
809 809 lf_node = file_node.get_largefile_node()
810 810 if lf_node:
811 811 # overwrite our pointer with the REAL large-file
812 812 file_node = lf_node
813 813
814 814 disposition = self._get_attachement_headers(f_path)
815 815
816 816 def stream_node():
817 817 yield file_node.raw_bytes
818 818
819 819 response = Response(app_iter=stream_node())
820 820 response.content_disposition = disposition
821 821 response.content_type = file_node.mimetype
822 822
823 823 charset = self._get_default_encoding(c)
824 824 if charset:
825 825 response.charset = charset
826 826
827 827 return response
828 828
829 829 def _get_nodelist_at_commit(self, repo_name, repo_id, commit_id, f_path):
830 830
831 831 cache_seconds = safe_int(
832 832 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
833 833 cache_on = cache_seconds > 0
834 834 log.debug(
835 835 'Computing FILE SEARCH for repo_id %s commit_id `%s` and path `%s`'
836 836 'with caching: %s[TTL: %ss]' % (
837 837 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
838 838
839 839 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
840 840 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
841 841
842 842 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
843 843 condition=cache_on)
844 844 def compute_file_search(repo_id, commit_id, f_path):
845 845 log.debug('Generating cached nodelist for repo_id:%s, %s, %s',
846 846 repo_id, commit_id, f_path)
847 847 try:
848 848 _d, _f = ScmModel().get_nodes(
849 849 repo_name, commit_id, f_path, flat=False)
850 850 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
851 851 log.exception(safe_str(e))
852 852 h.flash(safe_str(h.escape(e)), category='error')
853 853 raise HTTPFound(h.route_path(
854 854 'repo_files', repo_name=self.db_repo_name,
855 855 commit_id='tip', f_path='/'))
856 856 return _d + _f
857 857
858 858 return compute_file_search(self.db_repo.repo_id, commit_id, f_path)
859 859
860 860 @LoginRequired()
861 861 @HasRepoPermissionAnyDecorator(
862 862 'repository.read', 'repository.write', 'repository.admin')
863 863 @view_config(
864 864 route_name='repo_files_nodelist', request_method='GET',
865 865 renderer='json_ext', xhr=True)
866 866 def repo_nodelist(self):
867 867 self.load_default_context()
868 868
869 869 commit_id, f_path = self._get_commit_and_path()
870 870 commit = self._get_commit_or_redirect(commit_id)
871 871
872 872 metadata = self._get_nodelist_at_commit(
873 873 self.db_repo_name, self.db_repo.repo_id, commit.raw_id, f_path)
874 874 return {'nodes': metadata}
875 875
876 def _create_references(
877 self, branches_or_tags, symbolic_reference, f_path):
876 def _create_references(self, branches_or_tags, symbolic_reference, f_path, ref_type):
878 877 items = []
879 878 for name, commit_id in branches_or_tags.items():
880 sym_ref = symbolic_reference(commit_id, name, f_path)
881 items.append((sym_ref, name))
879 sym_ref = symbolic_reference(commit_id, name, f_path, ref_type)
880 items.append((sym_ref, name, ref_type))
882 881 return items
883 882
884 def _symbolic_reference(self, commit_id, name, f_path):
883 def _symbolic_reference(self, commit_id, name, f_path, ref_type):
885 884 return commit_id
886 885
887 def _symbolic_reference_svn(self, commit_id, name, f_path):
886 def _symbolic_reference_svn(self, commit_id, name, f_path, ref_type):
888 887 new_f_path = vcspath.join(name, f_path)
889 888 return u'%s@%s' % (new_f_path, commit_id)
890 889
891 890 def _get_node_history(self, commit_obj, f_path, commits=None):
892 891 """
893 892 get commit history for given node
894 893
895 894 :param commit_obj: commit to calculate history
896 895 :param f_path: path for node to calculate history for
897 896 :param commits: if passed don't calculate history and take
898 897 commits defined in this list
899 898 """
900 899 _ = self.request.translate
901 900
902 901 # calculate history based on tip
903 902 tip = self.rhodecode_vcs_repo.get_commit()
904 903 if commits is None:
905 904 pre_load = ["author", "branch"]
906 905 try:
907 906 commits = tip.get_path_history(f_path, pre_load=pre_load)
908 907 except (NodeDoesNotExistError, CommitError):
909 908 # this node is not present at tip!
910 909 commits = commit_obj.get_path_history(f_path, pre_load=pre_load)
911 910
912 911 history = []
913 912 commits_group = ([], _("Changesets"))
914 913 for commit in commits:
915 914 branch = ' (%s)' % commit.branch if commit.branch else ''
916 915 n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch)
917 commits_group[0].append((commit.raw_id, n_desc,))
916 commits_group[0].append((commit.raw_id, n_desc, 'sha'))
918 917 history.append(commits_group)
919 918
920 919 symbolic_reference = self._symbolic_reference
921 920
922 921 if self.rhodecode_vcs_repo.alias == 'svn':
923 922 adjusted_f_path = RepoFilesView.adjust_file_path_for_svn(
924 923 f_path, self.rhodecode_vcs_repo)
925 924 if adjusted_f_path != f_path:
926 925 log.debug(
927 926 'Recognized svn tag or branch in file "%s", using svn '
928 927 'specific symbolic references', f_path)
929 928 f_path = adjusted_f_path
930 929 symbolic_reference = self._symbolic_reference_svn
931 930
932 931 branches = self._create_references(
933 self.rhodecode_vcs_repo.branches, symbolic_reference, f_path)
932 self.rhodecode_vcs_repo.branches, symbolic_reference, f_path, 'branch')
934 933 branches_group = (branches, _("Branches"))
935 934
936 935 tags = self._create_references(
937 self.rhodecode_vcs_repo.tags, symbolic_reference, f_path)
936 self.rhodecode_vcs_repo.tags, symbolic_reference, f_path, 'tag')
938 937 tags_group = (tags, _("Tags"))
939 938
940 939 history.append(branches_group)
941 940 history.append(tags_group)
942 941
943 942 return history, commits
944 943
945 944 @LoginRequired()
946 945 @HasRepoPermissionAnyDecorator(
947 946 'repository.read', 'repository.write', 'repository.admin')
948 947 @view_config(
949 948 route_name='repo_file_history', request_method='GET',
950 949 renderer='json_ext')
951 950 def repo_file_history(self):
952 951 self.load_default_context()
953 952
954 953 commit_id, f_path = self._get_commit_and_path()
955 954 commit = self._get_commit_or_redirect(commit_id)
956 955 file_node = self._get_filenode_or_redirect(commit, f_path)
957 956
958 957 if file_node.is_file():
959 958 file_history, _hist = self._get_node_history(commit, f_path)
960 959
961 960 res = []
962 961 for obj in file_history:
963 962 res.append({
964 963 'text': obj[1],
965 'children': [{'id': o[0], 'text': o[1]} for o in obj[0]]
964 'children': [{'id': o[0], 'text': o[1], 'type': o[2]} for o in obj[0]]
966 965 })
967 966
968 967 data = {
969 968 'more': False,
970 969 'results': res
971 970 }
972 971 return data
973 972
974 973 log.warning('Cannot fetch history for directory')
975 974 raise HTTPBadRequest()
976 975
977 976 @LoginRequired()
978 977 @HasRepoPermissionAnyDecorator(
979 978 'repository.read', 'repository.write', 'repository.admin')
980 979 @view_config(
981 980 route_name='repo_file_authors', request_method='GET',
982 981 renderer='rhodecode:templates/files/file_authors_box.mako')
983 982 def repo_file_authors(self):
984 983 c = self.load_default_context()
985 984
986 985 commit_id, f_path = self._get_commit_and_path()
987 986 commit = self._get_commit_or_redirect(commit_id)
988 987 file_node = self._get_filenode_or_redirect(commit, f_path)
989 988
990 989 if not file_node.is_file():
991 990 raise HTTPBadRequest()
992 991
993 992 c.file_last_commit = file_node.last_commit
994 993 if self.request.GET.get('annotate') == '1':
995 994 # use _hist from annotation if annotation mode is on
996 995 commit_ids = set(x[1] for x in file_node.annotate)
997 996 _hist = (
998 997 self.rhodecode_vcs_repo.get_commit(commit_id)
999 998 for commit_id in commit_ids)
1000 999 else:
1001 1000 _f_history, _hist = self._get_node_history(commit, f_path)
1002 1001 c.file_author = False
1003 1002
1004 1003 unique = collections.OrderedDict()
1005 1004 for commit in _hist:
1006 1005 author = commit.author
1007 1006 if author not in unique:
1008 1007 unique[commit.author] = [
1009 1008 h.email(author),
1010 1009 h.person(author, 'username_or_name_or_email'),
1011 1010 1 # counter
1012 1011 ]
1013 1012
1014 1013 else:
1015 1014 # increase counter
1016 1015 unique[commit.author][2] += 1
1017 1016
1018 1017 c.authors = [val for val in unique.values()]
1019 1018
1020 1019 return self._get_template_context(c)
1021 1020
1022 1021 @LoginRequired()
1023 1022 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1024 1023 @view_config(
1025 1024 route_name='repo_files_remove_file', request_method='GET',
1026 1025 renderer='rhodecode:templates/files/files_delete.mako')
1027 1026 def repo_files_remove_file(self):
1028 1027 _ = self.request.translate
1029 1028 c = self.load_default_context()
1030 1029 commit_id, f_path = self._get_commit_and_path()
1031 1030
1032 1031 self._ensure_not_locked()
1033 1032 _branch_name, _sha_commit_id, is_head = \
1034 1033 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1035 1034
1036 1035 if not is_head:
1037 1036 h.flash(_('You can only delete files with commit '
1038 1037 'being a valid branch head.'), category='warning')
1039 1038 raise HTTPFound(
1040 1039 h.route_path('repo_files',
1041 1040 repo_name=self.db_repo_name, commit_id='tip',
1042 1041 f_path=f_path))
1043 1042
1044 1043 self.check_branch_permission(_branch_name)
1045 1044 c.commit = self._get_commit_or_redirect(commit_id)
1046 1045 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1047 1046
1048 1047 c.default_message = _(
1049 1048 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1050 1049 c.f_path = f_path
1051 1050
1052 1051 return self._get_template_context(c)
1053 1052
1054 1053 @LoginRequired()
1055 1054 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1056 1055 @CSRFRequired()
1057 1056 @view_config(
1058 1057 route_name='repo_files_delete_file', request_method='POST',
1059 1058 renderer=None)
1060 1059 def repo_files_delete_file(self):
1061 1060 _ = self.request.translate
1062 1061
1063 1062 c = self.load_default_context()
1064 1063 commit_id, f_path = self._get_commit_and_path()
1065 1064
1066 1065 self._ensure_not_locked()
1067 1066 _branch_name, _sha_commit_id, is_head = \
1068 1067 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1069 1068
1070 1069 if not is_head:
1071 1070 h.flash(_('You can only delete files with commit '
1072 1071 'being a valid branch head.'), category='warning')
1073 1072 raise HTTPFound(
1074 1073 h.route_path('repo_files',
1075 1074 repo_name=self.db_repo_name, commit_id='tip',
1076 1075 f_path=f_path))
1077 1076 self.check_branch_permission(_branch_name)
1078 1077
1079 1078 c.commit = self._get_commit_or_redirect(commit_id)
1080 1079 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1081 1080
1082 1081 c.default_message = _(
1083 1082 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1084 1083 c.f_path = f_path
1085 1084 node_path = f_path
1086 1085 author = self._rhodecode_db_user.full_contact
1087 1086 message = self.request.POST.get('message') or c.default_message
1088 1087 try:
1089 1088 nodes = {
1090 1089 node_path: {
1091 1090 'content': ''
1092 1091 }
1093 1092 }
1094 1093 ScmModel().delete_nodes(
1095 1094 user=self._rhodecode_db_user.user_id, repo=self.db_repo,
1096 1095 message=message,
1097 1096 nodes=nodes,
1098 1097 parent_commit=c.commit,
1099 1098 author=author,
1100 1099 )
1101 1100
1102 1101 h.flash(
1103 1102 _('Successfully deleted file `{}`').format(
1104 1103 h.escape(f_path)), category='success')
1105 1104 except Exception:
1106 1105 log.exception('Error during commit operation')
1107 1106 h.flash(_('Error occurred during commit'), category='error')
1108 1107 raise HTTPFound(
1109 1108 h.route_path('repo_commit', repo_name=self.db_repo_name,
1110 1109 commit_id='tip'))
1111 1110
1112 1111 @LoginRequired()
1113 1112 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1114 1113 @view_config(
1115 1114 route_name='repo_files_edit_file', request_method='GET',
1116 1115 renderer='rhodecode:templates/files/files_edit.mako')
1117 1116 def repo_files_edit_file(self):
1118 1117 _ = self.request.translate
1119 1118 c = self.load_default_context()
1120 1119 commit_id, f_path = self._get_commit_and_path()
1121 1120
1122 1121 self._ensure_not_locked()
1123 1122 _branch_name, _sha_commit_id, is_head = \
1124 1123 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1125 1124
1126 1125 if not is_head:
1127 1126 h.flash(_('You can only edit files with commit '
1128 1127 'being a valid branch head.'), category='warning')
1129 1128 raise HTTPFound(
1130 1129 h.route_path('repo_files',
1131 1130 repo_name=self.db_repo_name, commit_id='tip',
1132 1131 f_path=f_path))
1133 1132 self.check_branch_permission(_branch_name)
1134 1133
1135 1134 c.commit = self._get_commit_or_redirect(commit_id)
1136 1135 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1137 1136
1138 1137 if c.file.is_binary:
1139 1138 files_url = h.route_path(
1140 1139 'repo_files',
1141 1140 repo_name=self.db_repo_name,
1142 1141 commit_id=c.commit.raw_id, f_path=f_path)
1143 1142 raise HTTPFound(files_url)
1144 1143
1145 1144 c.default_message = _(
1146 1145 'Edited file {} via RhodeCode Enterprise').format(f_path)
1147 1146 c.f_path = f_path
1148 1147
1149 1148 return self._get_template_context(c)
1150 1149
1151 1150 @LoginRequired()
1152 1151 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1153 1152 @CSRFRequired()
1154 1153 @view_config(
1155 1154 route_name='repo_files_update_file', request_method='POST',
1156 1155 renderer=None)
1157 1156 def repo_files_update_file(self):
1158 1157 _ = self.request.translate
1159 1158 c = self.load_default_context()
1160 1159 commit_id, f_path = self._get_commit_and_path()
1161 1160
1162 1161 self._ensure_not_locked()
1163 1162 _branch_name, _sha_commit_id, is_head = \
1164 1163 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1165 1164
1166 1165 if not is_head:
1167 1166 h.flash(_('You can only edit files with commit '
1168 1167 'being a valid branch head.'), category='warning')
1169 1168 raise HTTPFound(
1170 1169 h.route_path('repo_files',
1171 1170 repo_name=self.db_repo_name, commit_id='tip',
1172 1171 f_path=f_path))
1173 1172
1174 1173 self.check_branch_permission(_branch_name)
1175 1174
1176 1175 c.commit = self._get_commit_or_redirect(commit_id)
1177 1176 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1178 1177
1179 1178 if c.file.is_binary:
1180 1179 raise HTTPFound(
1181 1180 h.route_path('repo_files',
1182 1181 repo_name=self.db_repo_name,
1183 1182 commit_id=c.commit.raw_id,
1184 1183 f_path=f_path))
1185 1184
1186 1185 c.default_message = _(
1187 1186 'Edited file {} via RhodeCode Enterprise').format(f_path)
1188 1187 c.f_path = f_path
1189 1188 old_content = c.file.content
1190 1189 sl = old_content.splitlines(1)
1191 1190 first_line = sl[0] if sl else ''
1192 1191
1193 1192 r_post = self.request.POST
1194 1193 # line endings: 0 - Unix, 1 - Mac, 2 - DOS
1195 1194 line_ending_mode = detect_mode(first_line, 0)
1196 1195 content = convert_line_endings(r_post.get('content', ''), line_ending_mode)
1197 1196
1198 1197 message = r_post.get('message') or c.default_message
1199 1198 org_f_path = c.file.unicode_path
1200 1199 filename = r_post['filename']
1201 1200 org_filename = c.file.name
1202 1201
1203 1202 if content == old_content and filename == org_filename:
1204 1203 h.flash(_('No changes'), category='warning')
1205 1204 raise HTTPFound(
1206 1205 h.route_path('repo_commit', repo_name=self.db_repo_name,
1207 1206 commit_id='tip'))
1208 1207 try:
1209 1208 mapping = {
1210 1209 org_f_path: {
1211 1210 'org_filename': org_f_path,
1212 1211 'filename': os.path.join(c.file.dir_path, filename),
1213 1212 'content': content,
1214 1213 'lexer': '',
1215 1214 'op': 'mod',
1216 1215 'mode': c.file.mode
1217 1216 }
1218 1217 }
1219 1218
1220 1219 ScmModel().update_nodes(
1221 1220 user=self._rhodecode_db_user.user_id,
1222 1221 repo=self.db_repo,
1223 1222 message=message,
1224 1223 nodes=mapping,
1225 1224 parent_commit=c.commit,
1226 1225 )
1227 1226
1228 1227 h.flash(
1229 1228 _('Successfully committed changes to file `{}`').format(
1230 1229 h.escape(f_path)), category='success')
1231 1230 except Exception:
1232 1231 log.exception('Error occurred during commit')
1233 1232 h.flash(_('Error occurred during commit'), category='error')
1234 1233 raise HTTPFound(
1235 1234 h.route_path('repo_commit', repo_name=self.db_repo_name,
1236 1235 commit_id='tip'))
1237 1236
1238 1237 @LoginRequired()
1239 1238 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1240 1239 @view_config(
1241 1240 route_name='repo_files_add_file', request_method='GET',
1242 1241 renderer='rhodecode:templates/files/files_add.mako')
1243 1242 def repo_files_add_file(self):
1244 1243 _ = self.request.translate
1245 1244 c = self.load_default_context()
1246 1245 commit_id, f_path = self._get_commit_and_path()
1247 1246
1248 1247 self._ensure_not_locked()
1249 1248
1250 1249 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1251 1250 if c.commit is None:
1252 1251 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1253 1252 c.default_message = (_('Added file via RhodeCode Enterprise'))
1254 1253 c.f_path = f_path.lstrip('/') # ensure not relative path
1255 1254
1256 1255 if self.rhodecode_vcs_repo.is_empty:
1257 1256 # for empty repository we cannot check for current branch, we rely on
1258 1257 # c.commit.branch instead
1259 1258 _branch_name = c.commit.branch
1260 1259 is_head = True
1261 1260 else:
1262 1261 _branch_name, _sha_commit_id, is_head = \
1263 1262 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1264 1263
1265 1264 if not is_head:
1266 1265 h.flash(_('You can only add files with commit '
1267 1266 'being a valid branch head.'), category='warning')
1268 1267 raise HTTPFound(
1269 1268 h.route_path('repo_files',
1270 1269 repo_name=self.db_repo_name, commit_id='tip',
1271 1270 f_path=f_path))
1272 1271
1273 1272 self.check_branch_permission(_branch_name)
1274 1273
1275 1274 return self._get_template_context(c)
1276 1275
1277 1276 @LoginRequired()
1278 1277 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1279 1278 @CSRFRequired()
1280 1279 @view_config(
1281 1280 route_name='repo_files_create_file', request_method='POST',
1282 1281 renderer=None)
1283 1282 def repo_files_create_file(self):
1284 1283 _ = self.request.translate
1285 1284 c = self.load_default_context()
1286 1285 commit_id, f_path = self._get_commit_and_path()
1287 1286
1288 1287 self._ensure_not_locked()
1289 1288
1290 1289 r_post = self.request.POST
1291 1290
1292 1291 c.commit = self._get_commit_or_redirect(
1293 1292 commit_id, redirect_after=False)
1294 1293 if c.commit is None:
1295 1294 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1296 1295
1297 1296 if self.rhodecode_vcs_repo.is_empty:
1298 1297 # for empty repository we cannot check for current branch, we rely on
1299 1298 # c.commit.branch instead
1300 1299 _branch_name = c.commit.branch
1301 1300 is_head = True
1302 1301 else:
1303 1302 _branch_name, _sha_commit_id, is_head = \
1304 1303 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1305 1304
1306 1305 if not is_head:
1307 1306 h.flash(_('You can only add files with commit '
1308 1307 'being a valid branch head.'), category='warning')
1309 1308 raise HTTPFound(
1310 1309 h.route_path('repo_files',
1311 1310 repo_name=self.db_repo_name, commit_id='tip',
1312 1311 f_path=f_path))
1313 1312
1314 1313 self.check_branch_permission(_branch_name)
1315 1314
1316 1315 c.default_message = (_('Added file via RhodeCode Enterprise'))
1317 1316 c.f_path = f_path
1318 1317 unix_mode = 0
1319 1318 content = convert_line_endings(r_post.get('content', ''), unix_mode)
1320 1319
1321 1320 message = r_post.get('message') or c.default_message
1322 1321 filename = r_post.get('filename')
1323 1322 location = r_post.get('location', '') # dir location
1324 1323 file_obj = r_post.get('upload_file', None)
1325 1324
1326 1325 if file_obj is not None and hasattr(file_obj, 'filename'):
1327 1326 filename = r_post.get('filename_upload')
1328 1327 content = file_obj.file
1329 1328
1330 1329 if hasattr(content, 'file'):
1331 1330 # non posix systems store real file under file attr
1332 1331 content = content.file
1333 1332
1334 1333 if self.rhodecode_vcs_repo.is_empty:
1335 1334 default_redirect_url = h.route_path(
1336 1335 'repo_summary', repo_name=self.db_repo_name)
1337 1336 else:
1338 1337 default_redirect_url = h.route_path(
1339 1338 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1340 1339
1341 1340 # If there's no commit, redirect to repo summary
1342 1341 if type(c.commit) is EmptyCommit:
1343 1342 redirect_url = h.route_path(
1344 1343 'repo_summary', repo_name=self.db_repo_name)
1345 1344 else:
1346 1345 redirect_url = default_redirect_url
1347 1346
1348 1347 if not filename:
1349 1348 h.flash(_('No filename'), category='warning')
1350 1349 raise HTTPFound(redirect_url)
1351 1350
1352 1351 # extract the location from filename,
1353 1352 # allows using foo/bar.txt syntax to create subdirectories
1354 1353 subdir_loc = filename.rsplit('/', 1)
1355 1354 if len(subdir_loc) == 2:
1356 1355 location = os.path.join(location, subdir_loc[0])
1357 1356
1358 1357 # strip all crap out of file, just leave the basename
1359 1358 filename = os.path.basename(filename)
1360 1359 node_path = os.path.join(location, filename)
1361 1360 author = self._rhodecode_db_user.full_contact
1362 1361
1363 1362 try:
1364 1363 nodes = {
1365 1364 node_path: {
1366 1365 'content': content
1367 1366 }
1368 1367 }
1369 1368 ScmModel().create_nodes(
1370 1369 user=self._rhodecode_db_user.user_id,
1371 1370 repo=self.db_repo,
1372 1371 message=message,
1373 1372 nodes=nodes,
1374 1373 parent_commit=c.commit,
1375 1374 author=author,
1376 1375 )
1377 1376
1378 1377 h.flash(
1379 1378 _('Successfully committed new file `{}`').format(
1380 1379 h.escape(node_path)), category='success')
1381 1380 except NonRelativePathError:
1382 1381 log.exception('Non Relative path found')
1383 1382 h.flash(_(
1384 1383 'The location specified must be a relative path and must not '
1385 1384 'contain .. in the path'), category='warning')
1386 1385 raise HTTPFound(default_redirect_url)
1387 1386 except (NodeError, NodeAlreadyExistsError) as e:
1388 1387 h.flash(_(h.escape(e)), category='error')
1389 1388 except Exception:
1390 1389 log.exception('Error occurred during commit')
1391 1390 h.flash(_('Error occurred during commit'), category='error')
1392 1391
1393 1392 raise HTTPFound(default_redirect_url)
@@ -1,2050 +1,2057 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2019 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 """
22 22 Helper functions
23 23
24 24 Consists of functions to typically be used within templates, but also
25 25 available to Controllers. This module is available to both as 'h'.
26 26 """
27 27
28 28 import os
29 29 import random
30 30 import hashlib
31 31 import StringIO
32 32 import textwrap
33 33 import urllib
34 34 import math
35 35 import logging
36 36 import re
37 37 import time
38 38 import string
39 39 import hashlib
40 40 from collections import OrderedDict
41 41
42 42 import pygments
43 43 import itertools
44 44 import fnmatch
45 45 import bleach
46 46
47 47 from pyramid import compat
48 48 from datetime import datetime
49 49 from functools import partial
50 50 from pygments.formatters.html import HtmlFormatter
51 51 from pygments.lexers import (
52 52 get_lexer_by_name, get_lexer_for_filename, get_lexer_for_mimetype)
53 53
54 54 from pyramid.threadlocal import get_current_request
55 55
56 56 from webhelpers.html import literal, HTML, escape
57 57 from webhelpers.html.tools import *
58 58 from webhelpers.html.builder import make_tag
59 59 from webhelpers.html.tags import auto_discovery_link, checkbox, css_classes, \
60 60 end_form, file, form as wh_form, hidden, image, javascript_link, link_to, \
61 61 link_to_if, link_to_unless, ol, required_legend, select, stylesheet_link, \
62 62 submit, text, password, textarea, title, ul, xml_declaration, radio
63 63 from webhelpers.html.tools import auto_link, button_to, highlight, \
64 64 js_obfuscate, mail_to, strip_links, strip_tags, tag_re
65 65 from webhelpers.text import chop_at, collapse, convert_accented_entities, \
66 66 convert_misc_entities, lchop, plural, rchop, remove_formatting, \
67 67 replace_whitespace, urlify, truncate, wrap_paragraphs
68 68 from webhelpers.date import time_ago_in_words
69 69 from webhelpers.paginate import Page as _Page
70 70 from webhelpers.html.tags import _set_input_attrs, _set_id_attr, \
71 71 convert_boolean_attrs, NotGiven, _make_safe_id_component
72 72 from webhelpers2.number import format_byte_size
73 73
74 74 from rhodecode.lib.action_parser import action_parser
75 75 from rhodecode.lib.ext_json import json
76 76 from rhodecode.lib.utils import repo_name_slug, get_custom_lexer
77 77 from rhodecode.lib.utils2 import str2bool, safe_unicode, safe_str, \
78 78 get_commit_safe, datetime_to_time, time_to_datetime, time_to_utcdatetime, \
79 79 AttributeDict, safe_int, md5, md5_safe
80 80 from rhodecode.lib.markup_renderer import MarkupRenderer, relative_links
81 81 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
82 82 from rhodecode.lib.vcs.backends.base import BaseChangeset, EmptyCommit
83 83 from rhodecode.lib.index.search_utils import get_matching_line_offsets
84 84 from rhodecode.config.conf import DATE_FORMAT, DATETIME_FORMAT
85 85 from rhodecode.model.changeset_status import ChangesetStatusModel
86 86 from rhodecode.model.db import Permission, User, Repository
87 87 from rhodecode.model.repo_group import RepoGroupModel
88 88 from rhodecode.model.settings import IssueTrackerSettingsModel
89 89
90 90
91 91 log = logging.getLogger(__name__)
92 92
93 93
94 94 DEFAULT_USER = User.DEFAULT_USER
95 95 DEFAULT_USER_EMAIL = User.DEFAULT_USER_EMAIL
96 96
97 97
98 98 def asset(path, ver=None, **kwargs):
99 99 """
100 100 Helper to generate a static asset file path for rhodecode assets
101 101
102 102 eg. h.asset('images/image.png', ver='3923')
103 103
104 104 :param path: path of asset
105 105 :param ver: optional version query param to append as ?ver=
106 106 """
107 107 request = get_current_request()
108 108 query = {}
109 109 query.update(kwargs)
110 110 if ver:
111 111 query = {'ver': ver}
112 112 return request.static_path(
113 113 'rhodecode:public/{}'.format(path), _query=query)
114 114
115 115
116 116 default_html_escape_table = {
117 117 ord('&'): u'&amp;',
118 118 ord('<'): u'&lt;',
119 119 ord('>'): u'&gt;',
120 120 ord('"'): u'&quot;',
121 121 ord("'"): u'&#39;',
122 122 }
123 123
124 124
125 125 def html_escape(text, html_escape_table=default_html_escape_table):
126 126 """Produce entities within text."""
127 127 return text.translate(html_escape_table)
128 128
129 129
130 130 def chop_at_smart(s, sub, inclusive=False, suffix_if_chopped=None):
131 131 """
132 132 Truncate string ``s`` at the first occurrence of ``sub``.
133 133
134 134 If ``inclusive`` is true, truncate just after ``sub`` rather than at it.
135 135 """
136 136 suffix_if_chopped = suffix_if_chopped or ''
137 137 pos = s.find(sub)
138 138 if pos == -1:
139 139 return s
140 140
141 141 if inclusive:
142 142 pos += len(sub)
143 143
144 144 chopped = s[:pos]
145 145 left = s[pos:].strip()
146 146
147 147 if left and suffix_if_chopped:
148 148 chopped += suffix_if_chopped
149 149
150 150 return chopped
151 151
152 152
153 153 def shorter(text, size=20):
154 154 postfix = '...'
155 155 if len(text) > size:
156 156 return text[:size - len(postfix)] + postfix
157 157 return text
158 158
159 159
160 160 def _reset(name, value=None, id=NotGiven, type="reset", **attrs):
161 161 """
162 162 Reset button
163 163 """
164 164 _set_input_attrs(attrs, type, name, value)
165 165 _set_id_attr(attrs, id, name)
166 166 convert_boolean_attrs(attrs, ["disabled"])
167 167 return HTML.input(**attrs)
168 168
169 169 reset = _reset
170 170 safeid = _make_safe_id_component
171 171
172 172
173 173 def branding(name, length=40):
174 174 return truncate(name, length, indicator="")
175 175
176 176
177 177 def FID(raw_id, path):
178 178 """
179 179 Creates a unique ID for filenode based on it's hash of path and commit
180 180 it's safe to use in urls
181 181
182 182 :param raw_id:
183 183 :param path:
184 184 """
185 185
186 186 return 'c-%s-%s' % (short_id(raw_id), md5_safe(path)[:12])
187 187
188 188
189 189 class _GetError(object):
190 190 """Get error from form_errors, and represent it as span wrapped error
191 191 message
192 192
193 193 :param field_name: field to fetch errors for
194 194 :param form_errors: form errors dict
195 195 """
196 196
197 197 def __call__(self, field_name, form_errors):
198 198 tmpl = """<span class="error_msg">%s</span>"""
199 199 if form_errors and field_name in form_errors:
200 200 return literal(tmpl % form_errors.get(field_name))
201 201
202
202 203 get_error = _GetError()
203 204
204 205
205 206 class _ToolTip(object):
206 207
207 208 def __call__(self, tooltip_title, trim_at=50):
208 209 """
209 210 Special function just to wrap our text into nice formatted
210 211 autowrapped text
211 212
212 213 :param tooltip_title:
213 214 """
214 215 tooltip_title = escape(tooltip_title)
215 216 tooltip_title = tooltip_title.replace('<', '&lt;').replace('>', '&gt;')
216 217 return tooltip_title
217 218
219
218 220 tooltip = _ToolTip()
219 221
220 222
221 def files_breadcrumbs(repo_name, commit_id, file_path, at_ref=None):
223 def files_breadcrumbs(repo_name, commit_id, file_path, at_ref=None, limit_items=False):
222 224 if isinstance(file_path, str):
223 225 file_path = safe_unicode(file_path)
226
224 227 route_qry = {'at': at_ref} if at_ref else None
225 228
226 # TODO: johbo: Is this always a url like path, or is this operating
227 # system dependent?
228 path_segments = file_path.split('/')
229
230 repo_name_html = escape(repo_name)
231 if len(path_segments) == 1 and path_segments[0] == '':
232 url_segments = [repo_name_html]
233 else:
229 # first segment is a `..` link to repo files
230 root_name = literal(u'<i class="icon-home"></i>')
234 231 url_segments = [
235 232 link_to(
236 repo_name_html,
233 root_name,
237 234 route_path(
238 235 'repo_files',
239 236 repo_name=repo_name,
240 237 commit_id=commit_id,
241 238 f_path='',
242 239 _query=route_qry),
243 240 )]
244 241
242 path_segments = file_path.split('/')
245 243 last_cnt = len(path_segments) - 1
246 244 for cnt, segment in enumerate(path_segments):
247 245 if not segment:
248 246 continue
249 247 segment_html = escape(segment)
250 248
251 249 if cnt != last_cnt:
252 250 url_segments.append(
253 251 link_to(
254 252 segment_html,
255 253 route_path(
256 254 'repo_files',
257 255 repo_name=repo_name,
258 256 commit_id=commit_id,
259 257 f_path='/'.join(path_segments[:cnt + 1]),
260 258 _query=route_qry),
261 259 ))
262 260 else:
263 261 url_segments.append(segment_html)
264 262
265 return literal('/'.join(url_segments))
263 limited_url_segments = url_segments[:1] + ['...'] + url_segments[-5:]
264 if limit_items and len(limited_url_segments) < len(url_segments):
265 url_segments = limited_url_segments
266
267 full_path = file_path
268 icon = '<i class="file-breadcrumb-copy tooltip icon-clipboard clipboard-action" data-clipboard-text="{}" title="Copy the full path"></i>'.format(full_path)
269 if file_path == '':
270 return root_name
271 else:
272 return literal(' / '.join(url_segments) + icon)
266 273
267 274
268 275 def code_highlight(code, lexer, formatter, use_hl_filter=False):
269 276 """
270 277 Lex ``code`` with ``lexer`` and format it with the formatter ``formatter``.
271 278
272 279 If ``outfile`` is given and a valid file object (an object
273 280 with a ``write`` method), the result will be written to it, otherwise
274 281 it is returned as a string.
275 282 """
276 283 if use_hl_filter:
277 284 # add HL filter
278 285 from rhodecode.lib.index import search_utils
279 286 lexer.add_filter(search_utils.ElasticSearchHLFilter())
280 287 return pygments.format(pygments.lex(code, lexer), formatter)
281 288
282 289
283 290 class CodeHtmlFormatter(HtmlFormatter):
284 291 """
285 292 My code Html Formatter for source codes
286 293 """
287 294
288 295 def wrap(self, source, outfile):
289 296 return self._wrap_div(self._wrap_pre(self._wrap_code(source)))
290 297
291 298 def _wrap_code(self, source):
292 299 for cnt, it in enumerate(source):
293 300 i, t = it
294 301 t = '<div id="L%s">%s</div>' % (cnt + 1, t)
295 302 yield i, t
296 303
297 304 def _wrap_tablelinenos(self, inner):
298 305 dummyoutfile = StringIO.StringIO()
299 306 lncount = 0
300 307 for t, line in inner:
301 308 if t:
302 309 lncount += 1
303 310 dummyoutfile.write(line)
304 311
305 312 fl = self.linenostart
306 313 mw = len(str(lncount + fl - 1))
307 314 sp = self.linenospecial
308 315 st = self.linenostep
309 316 la = self.lineanchors
310 317 aln = self.anchorlinenos
311 318 nocls = self.noclasses
312 319 if sp:
313 320 lines = []
314 321
315 322 for i in range(fl, fl + lncount):
316 323 if i % st == 0:
317 324 if i % sp == 0:
318 325 if aln:
319 326 lines.append('<a href="#%s%d" class="special">%*d</a>' %
320 327 (la, i, mw, i))
321 328 else:
322 329 lines.append('<span class="special">%*d</span>' % (mw, i))
323 330 else:
324 331 if aln:
325 332 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
326 333 else:
327 334 lines.append('%*d' % (mw, i))
328 335 else:
329 336 lines.append('')
330 337 ls = '\n'.join(lines)
331 338 else:
332 339 lines = []
333 340 for i in range(fl, fl + lncount):
334 341 if i % st == 0:
335 342 if aln:
336 343 lines.append('<a href="#%s%d">%*d</a>' % (la, i, mw, i))
337 344 else:
338 345 lines.append('%*d' % (mw, i))
339 346 else:
340 347 lines.append('')
341 348 ls = '\n'.join(lines)
342 349
343 350 # in case you wonder about the seemingly redundant <div> here: since the
344 351 # content in the other cell also is wrapped in a div, some browsers in
345 352 # some configurations seem to mess up the formatting...
346 353 if nocls:
347 354 yield 0, ('<table class="%stable">' % self.cssclass +
348 355 '<tr><td><div class="linenodiv" '
349 356 'style="background-color: #f0f0f0; padding-right: 10px">'
350 357 '<pre style="line-height: 125%">' +
351 358 ls + '</pre></div></td><td id="hlcode" class="code">')
352 359 else:
353 360 yield 0, ('<table class="%stable">' % self.cssclass +
354 361 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
355 362 ls + '</pre></div></td><td id="hlcode" class="code">')
356 363 yield 0, dummyoutfile.getvalue()
357 364 yield 0, '</td></tr></table>'
358 365
359 366
360 367 class SearchContentCodeHtmlFormatter(CodeHtmlFormatter):
361 368 def __init__(self, **kw):
362 369 # only show these line numbers if set
363 370 self.only_lines = kw.pop('only_line_numbers', [])
364 371 self.query_terms = kw.pop('query_terms', [])
365 372 self.max_lines = kw.pop('max_lines', 5)
366 373 self.line_context = kw.pop('line_context', 3)
367 374 self.url = kw.pop('url', None)
368 375
369 376 super(CodeHtmlFormatter, self).__init__(**kw)
370 377
371 378 def _wrap_code(self, source):
372 379 for cnt, it in enumerate(source):
373 380 i, t = it
374 381 t = '<pre>%s</pre>' % t
375 382 yield i, t
376 383
377 384 def _wrap_tablelinenos(self, inner):
378 385 yield 0, '<table class="code-highlight %stable">' % self.cssclass
379 386
380 387 last_shown_line_number = 0
381 388 current_line_number = 1
382 389
383 390 for t, line in inner:
384 391 if not t:
385 392 yield t, line
386 393 continue
387 394
388 395 if current_line_number in self.only_lines:
389 396 if last_shown_line_number + 1 != current_line_number:
390 397 yield 0, '<tr>'
391 398 yield 0, '<td class="line">...</td>'
392 399 yield 0, '<td id="hlcode" class="code"></td>'
393 400 yield 0, '</tr>'
394 401
395 402 yield 0, '<tr>'
396 403 if self.url:
397 404 yield 0, '<td class="line"><a href="%s#L%i">%i</a></td>' % (
398 405 self.url, current_line_number, current_line_number)
399 406 else:
400 407 yield 0, '<td class="line"><a href="">%i</a></td>' % (
401 408 current_line_number)
402 409 yield 0, '<td id="hlcode" class="code">' + line + '</td>'
403 410 yield 0, '</tr>'
404 411
405 412 last_shown_line_number = current_line_number
406 413
407 414 current_line_number += 1
408 415
409 416 yield 0, '</table>'
410 417
411 418
412 419 def hsv_to_rgb(h, s, v):
413 420 """ Convert hsv color values to rgb """
414 421
415 422 if s == 0.0:
416 423 return v, v, v
417 424 i = int(h * 6.0) # XXX assume int() truncates!
418 425 f = (h * 6.0) - i
419 426 p = v * (1.0 - s)
420 427 q = v * (1.0 - s * f)
421 428 t = v * (1.0 - s * (1.0 - f))
422 429 i = i % 6
423 430 if i == 0:
424 431 return v, t, p
425 432 if i == 1:
426 433 return q, v, p
427 434 if i == 2:
428 435 return p, v, t
429 436 if i == 3:
430 437 return p, q, v
431 438 if i == 4:
432 439 return t, p, v
433 440 if i == 5:
434 441 return v, p, q
435 442
436 443
437 444 def unique_color_generator(n=10000, saturation=0.10, lightness=0.95):
438 445 """
439 446 Generator for getting n of evenly distributed colors using
440 447 hsv color and golden ratio. It always return same order of colors
441 448
442 449 :param n: number of colors to generate
443 450 :param saturation: saturation of returned colors
444 451 :param lightness: lightness of returned colors
445 452 :returns: RGB tuple
446 453 """
447 454
448 455 golden_ratio = 0.618033988749895
449 456 h = 0.22717784590367374
450 457
451 458 for _ in xrange(n):
452 459 h += golden_ratio
453 460 h %= 1
454 461 HSV_tuple = [h, saturation, lightness]
455 462 RGB_tuple = hsv_to_rgb(*HSV_tuple)
456 463 yield map(lambda x: str(int(x * 256)), RGB_tuple)
457 464
458 465
459 466 def color_hasher(n=10000, saturation=0.10, lightness=0.95):
460 467 """
461 468 Returns a function which when called with an argument returns a unique
462 469 color for that argument, eg.
463 470
464 471 :param n: number of colors to generate
465 472 :param saturation: saturation of returned colors
466 473 :param lightness: lightness of returned colors
467 474 :returns: css RGB string
468 475
469 476 >>> color_hash = color_hasher()
470 477 >>> color_hash('hello')
471 478 'rgb(34, 12, 59)'
472 479 >>> color_hash('hello')
473 480 'rgb(34, 12, 59)'
474 481 >>> color_hash('other')
475 482 'rgb(90, 224, 159)'
476 483 """
477 484
478 485 color_dict = {}
479 486 cgenerator = unique_color_generator(
480 487 saturation=saturation, lightness=lightness)
481 488
482 489 def get_color_string(thing):
483 490 if thing in color_dict:
484 491 col = color_dict[thing]
485 492 else:
486 493 col = color_dict[thing] = cgenerator.next()
487 494 return "rgb(%s)" % (', '.join(col))
488 495
489 496 return get_color_string
490 497
491 498
492 499 def get_lexer_safe(mimetype=None, filepath=None):
493 500 """
494 501 Tries to return a relevant pygments lexer using mimetype/filepath name,
495 502 defaulting to plain text if none could be found
496 503 """
497 504 lexer = None
498 505 try:
499 506 if mimetype:
500 507 lexer = get_lexer_for_mimetype(mimetype)
501 508 if not lexer:
502 509 lexer = get_lexer_for_filename(filepath)
503 510 except pygments.util.ClassNotFound:
504 511 pass
505 512
506 513 if not lexer:
507 514 lexer = get_lexer_by_name('text')
508 515
509 516 return lexer
510 517
511 518
512 519 def get_lexer_for_filenode(filenode):
513 520 lexer = get_custom_lexer(filenode.extension) or filenode.lexer
514 521 return lexer
515 522
516 523
517 524 def pygmentize(filenode, **kwargs):
518 525 """
519 526 pygmentize function using pygments
520 527
521 528 :param filenode:
522 529 """
523 530 lexer = get_lexer_for_filenode(filenode)
524 531 return literal(code_highlight(filenode.content, lexer,
525 532 CodeHtmlFormatter(**kwargs)))
526 533
527 534
528 535 def is_following_repo(repo_name, user_id):
529 536 from rhodecode.model.scm import ScmModel
530 537 return ScmModel().is_following_repo(repo_name, user_id)
531 538
532 539
533 540 class _Message(object):
534 541 """A message returned by ``Flash.pop_messages()``.
535 542
536 543 Converting the message to a string returns the message text. Instances
537 544 also have the following attributes:
538 545
539 546 * ``message``: the message text.
540 547 * ``category``: the category specified when the message was created.
541 548 """
542 549
543 550 def __init__(self, category, message):
544 551 self.category = category
545 552 self.message = message
546 553
547 554 def __str__(self):
548 555 return self.message
549 556
550 557 __unicode__ = __str__
551 558
552 559 def __html__(self):
553 560 return escape(safe_unicode(self.message))
554 561
555 562
556 563 class Flash(object):
557 564 # List of allowed categories. If None, allow any category.
558 565 categories = ["warning", "notice", "error", "success"]
559 566
560 567 # Default category if none is specified.
561 568 default_category = "notice"
562 569
563 570 def __init__(self, session_key="flash", categories=None,
564 571 default_category=None):
565 572 """
566 573 Instantiate a ``Flash`` object.
567 574
568 575 ``session_key`` is the key to save the messages under in the user's
569 576 session.
570 577
571 578 ``categories`` is an optional list which overrides the default list
572 579 of categories.
573 580
574 581 ``default_category`` overrides the default category used for messages
575 582 when none is specified.
576 583 """
577 584 self.session_key = session_key
578 585 if categories is not None:
579 586 self.categories = categories
580 587 if default_category is not None:
581 588 self.default_category = default_category
582 589 if self.categories and self.default_category not in self.categories:
583 590 raise ValueError(
584 591 "unrecognized default category %r" % (self.default_category,))
585 592
586 593 def pop_messages(self, session=None, request=None):
587 594 """
588 595 Return all accumulated messages and delete them from the session.
589 596
590 597 The return value is a list of ``Message`` objects.
591 598 """
592 599 messages = []
593 600
594 601 if not session:
595 602 if not request:
596 603 request = get_current_request()
597 604 session = request.session
598 605
599 606 # Pop the 'old' pylons flash messages. They are tuples of the form
600 607 # (category, message)
601 608 for cat, msg in session.pop(self.session_key, []):
602 609 messages.append(_Message(cat, msg))
603 610
604 611 # Pop the 'new' pyramid flash messages for each category as list
605 612 # of strings.
606 613 for cat in self.categories:
607 614 for msg in session.pop_flash(queue=cat):
608 615 messages.append(_Message(cat, msg))
609 616 # Map messages from the default queue to the 'notice' category.
610 617 for msg in session.pop_flash():
611 618 messages.append(_Message('notice', msg))
612 619
613 620 session.save()
614 621 return messages
615 622
616 623 def json_alerts(self, session=None, request=None):
617 624 payloads = []
618 625 messages = flash.pop_messages(session=session, request=request)
619 626 if messages:
620 627 for message in messages:
621 628 subdata = {}
622 629 if hasattr(message.message, 'rsplit'):
623 630 flash_data = message.message.rsplit('|DELIM|', 1)
624 631 org_message = flash_data[0]
625 632 if len(flash_data) > 1:
626 633 subdata = json.loads(flash_data[1])
627 634 else:
628 635 org_message = message.message
629 636 payloads.append({
630 637 'message': {
631 638 'message': u'{}'.format(org_message),
632 639 'level': message.category,
633 640 'force': True,
634 641 'subdata': subdata
635 642 }
636 643 })
637 644 return json.dumps(payloads)
638 645
639 646 def __call__(self, message, category=None, ignore_duplicate=False,
640 647 session=None, request=None):
641 648
642 649 if not session:
643 650 if not request:
644 651 request = get_current_request()
645 652 session = request.session
646 653
647 654 session.flash(
648 655 message, queue=category, allow_duplicate=not ignore_duplicate)
649 656
650 657
651 658 flash = Flash()
652 659
653 660 #==============================================================================
654 661 # SCM FILTERS available via h.
655 662 #==============================================================================
656 663 from rhodecode.lib.vcs.utils import author_name, author_email
657 664 from rhodecode.lib.utils2 import credentials_filter, age, age_from_seconds
658 665 from rhodecode.model.db import User, ChangesetStatus
659 666
660 667 capitalize = lambda x: x.capitalize()
661 668 email = author_email
662 669 short_id = lambda x: x[:12]
663 670 hide_credentials = lambda x: ''.join(credentials_filter(x))
664 671
665 672
666 673 import pytz
667 674 import tzlocal
668 675 local_timezone = tzlocal.get_localzone()
669 676
670 677
671 678 def age_component(datetime_iso, value=None, time_is_local=False):
672 679 title = value or format_date(datetime_iso)
673 680 tzinfo = '+00:00'
674 681
675 682 # detect if we have a timezone info, otherwise, add it
676 683 if time_is_local and isinstance(datetime_iso, datetime) and not datetime_iso.tzinfo:
677 684 force_timezone = os.environ.get('RC_TIMEZONE', '')
678 685 if force_timezone:
679 686 force_timezone = pytz.timezone(force_timezone)
680 687 timezone = force_timezone or local_timezone
681 688 offset = timezone.localize(datetime_iso).strftime('%z')
682 689 tzinfo = '{}:{}'.format(offset[:-2], offset[-2:])
683 690
684 691 return literal(
685 692 '<time class="timeago tooltip" '
686 693 'title="{1}{2}" datetime="{0}{2}">{1}</time>'.format(
687 694 datetime_iso, title, tzinfo))
688 695
689 696
690 697 def _shorten_commit_id(commit_id, commit_len=None):
691 698 if commit_len is None:
692 699 request = get_current_request()
693 700 commit_len = request.call_context.visual.show_sha_length
694 701 return commit_id[:commit_len]
695 702
696 703
697 704 def show_id(commit, show_idx=None, commit_len=None):
698 705 """
699 706 Configurable function that shows ID
700 707 by default it's r123:fffeeefffeee
701 708
702 709 :param commit: commit instance
703 710 """
704 711 if show_idx is None:
705 712 request = get_current_request()
706 713 show_idx = request.call_context.visual.show_revision_number
707 714
708 715 raw_id = _shorten_commit_id(commit.raw_id, commit_len=commit_len)
709 716 if show_idx:
710 717 return 'r%s:%s' % (commit.idx, raw_id)
711 718 else:
712 719 return '%s' % (raw_id, )
713 720
714 721
715 722 def format_date(date):
716 723 """
717 724 use a standardized formatting for dates used in RhodeCode
718 725
719 726 :param date: date/datetime object
720 727 :return: formatted date
721 728 """
722 729
723 730 if date:
724 731 _fmt = "%a, %d %b %Y %H:%M:%S"
725 732 return safe_unicode(date.strftime(_fmt))
726 733
727 734 return u""
728 735
729 736
730 737 class _RepoChecker(object):
731 738
732 739 def __init__(self, backend_alias):
733 740 self._backend_alias = backend_alias
734 741
735 742 def __call__(self, repository):
736 743 if hasattr(repository, 'alias'):
737 744 _type = repository.alias
738 745 elif hasattr(repository, 'repo_type'):
739 746 _type = repository.repo_type
740 747 else:
741 748 _type = repository
742 749 return _type == self._backend_alias
743 750
744 751
745 752 is_git = _RepoChecker('git')
746 753 is_hg = _RepoChecker('hg')
747 754 is_svn = _RepoChecker('svn')
748 755
749 756
750 757 def get_repo_type_by_name(repo_name):
751 758 repo = Repository.get_by_repo_name(repo_name)
752 759 if repo:
753 760 return repo.repo_type
754 761
755 762
756 763 def is_svn_without_proxy(repository):
757 764 if is_svn(repository):
758 765 from rhodecode.model.settings import VcsSettingsModel
759 766 conf = VcsSettingsModel().get_ui_settings_as_config_obj()
760 767 return not str2bool(conf.get('vcs_svn_proxy', 'http_requests_enabled'))
761 768 return False
762 769
763 770
764 771 def discover_user(author):
765 772 """
766 773 Tries to discover RhodeCode User based on the autho string. Author string
767 774 is typically `FirstName LastName <email@address.com>`
768 775 """
769 776
770 777 # if author is already an instance use it for extraction
771 778 if isinstance(author, User):
772 779 return author
773 780
774 781 # Valid email in the attribute passed, see if they're in the system
775 782 _email = author_email(author)
776 783 if _email != '':
777 784 user = User.get_by_email(_email, case_insensitive=True, cache=True)
778 785 if user is not None:
779 786 return user
780 787
781 788 # Maybe it's a username, we try to extract it and fetch by username ?
782 789 _author = author_name(author)
783 790 user = User.get_by_username(_author, case_insensitive=True, cache=True)
784 791 if user is not None:
785 792 return user
786 793
787 794 return None
788 795
789 796
790 797 def email_or_none(author):
791 798 # extract email from the commit string
792 799 _email = author_email(author)
793 800
794 801 # If we have an email, use it, otherwise
795 802 # see if it contains a username we can get an email from
796 803 if _email != '':
797 804 return _email
798 805 else:
799 806 user = User.get_by_username(
800 807 author_name(author), case_insensitive=True, cache=True)
801 808
802 809 if user is not None:
803 810 return user.email
804 811
805 812 # No valid email, not a valid user in the system, none!
806 813 return None
807 814
808 815
809 816 def link_to_user(author, length=0, **kwargs):
810 817 user = discover_user(author)
811 818 # user can be None, but if we have it already it means we can re-use it
812 819 # in the person() function, so we save 1 intensive-query
813 820 if user:
814 821 author = user
815 822
816 823 display_person = person(author, 'username_or_name_or_email')
817 824 if length:
818 825 display_person = shorter(display_person, length)
819 826
820 827 if user:
821 828 return link_to(
822 829 escape(display_person),
823 830 route_path('user_profile', username=user.username),
824 831 **kwargs)
825 832 else:
826 833 return escape(display_person)
827 834
828 835
829 836 def link_to_group(users_group_name, **kwargs):
830 837 return link_to(
831 838 escape(users_group_name),
832 839 route_path('user_group_profile', user_group_name=users_group_name),
833 840 **kwargs)
834 841
835 842
836 843 def person(author, show_attr="username_and_name"):
837 844 user = discover_user(author)
838 845 if user:
839 846 return getattr(user, show_attr)
840 847 else:
841 848 _author = author_name(author)
842 849 _email = email(author)
843 850 return _author or _email
844 851
845 852
846 853 def author_string(email):
847 854 if email:
848 855 user = User.get_by_email(email, case_insensitive=True, cache=True)
849 856 if user:
850 857 if user.first_name or user.last_name:
851 858 return '%s %s &lt;%s&gt;' % (
852 859 user.first_name, user.last_name, email)
853 860 else:
854 861 return email
855 862 else:
856 863 return email
857 864 else:
858 865 return None
859 866
860 867
861 868 def person_by_id(id_, show_attr="username_and_name"):
862 869 # attr to return from fetched user
863 870 person_getter = lambda usr: getattr(usr, show_attr)
864 871
865 872 #maybe it's an ID ?
866 873 if str(id_).isdigit() or isinstance(id_, int):
867 874 id_ = int(id_)
868 875 user = User.get(id_)
869 876 if user is not None:
870 877 return person_getter(user)
871 878 return id_
872 879
873 880
874 881 def gravatar_with_user(request, author, show_disabled=False):
875 882 _render = request.get_partial_renderer(
876 883 'rhodecode:templates/base/base.mako')
877 884 return _render('gravatar_with_user', author, show_disabled=show_disabled)
878 885
879 886
880 887 tags_paterns = OrderedDict((
881 888 ('lang', (re.compile(r'\[(lang|language)\ \=\&gt;\ *([a-zA-Z\-\/\#\+\.]*)\]'),
882 889 '<div class="metatag" tag="lang">\\2</div>')),
883 890
884 891 ('see', (re.compile(r'\[see\ \=\&gt;\ *([a-zA-Z0-9\/\=\?\&amp;\ \:\/\.\-]*)\]'),
885 892 '<div class="metatag" tag="see">see: \\1 </div>')),
886 893
887 894 ('url', (re.compile(r'\[url\ \=\&gt;\ \[([a-zA-Z0-9\ \.\-\_]+)\]\((http://|https://|/)(.*?)\)\]'),
888 895 '<div class="metatag" tag="url"> <a href="\\2\\3">\\1</a> </div>')),
889 896
890 897 ('license', (re.compile(r'\[license\ \=\&gt;\ *([a-zA-Z0-9\/\=\?\&amp;\ \:\/\.\-]*)\]'),
891 898 '<div class="metatag" tag="license"><a href="http:\/\/www.opensource.org/licenses/\\1">\\1</a></div>')),
892 899
893 900 ('ref', (re.compile(r'\[(requires|recommends|conflicts|base)\ \=\&gt;\ *([a-zA-Z0-9\-\/]*)\]'),
894 901 '<div class="metatag" tag="ref \\1">\\1: <a href="/\\2">\\2</a></div>')),
895 902
896 903 ('state', (re.compile(r'\[(stable|featured|stale|dead|dev|deprecated)\]'),
897 904 '<div class="metatag" tag="state \\1">\\1</div>')),
898 905
899 906 # label in grey
900 907 ('label', (re.compile(r'\[([a-z]+)\]'),
901 908 '<div class="metatag" tag="label">\\1</div>')),
902 909
903 910 # generic catch all in grey
904 911 ('generic', (re.compile(r'\[([a-zA-Z0-9\.\-\_]+)\]'),
905 912 '<div class="metatag" tag="generic">\\1</div>')),
906 913 ))
907 914
908 915
909 916 def extract_metatags(value):
910 917 """
911 918 Extract supported meta-tags from given text value
912 919 """
913 920 tags = []
914 921 if not value:
915 922 return tags, ''
916 923
917 924 for key, val in tags_paterns.items():
918 925 pat, replace_html = val
919 926 tags.extend([(key, x.group()) for x in pat.finditer(value)])
920 927 value = pat.sub('', value)
921 928
922 929 return tags, value
923 930
924 931
925 932 def style_metatag(tag_type, value):
926 933 """
927 934 converts tags from value into html equivalent
928 935 """
929 936 if not value:
930 937 return ''
931 938
932 939 html_value = value
933 940 tag_data = tags_paterns.get(tag_type)
934 941 if tag_data:
935 942 pat, replace_html = tag_data
936 943 # convert to plain `unicode` instead of a markup tag to be used in
937 944 # regex expressions. safe_unicode doesn't work here
938 945 html_value = pat.sub(replace_html, unicode(value))
939 946
940 947 return html_value
941 948
942 949
943 950 def bool2icon(value, show_at_false=True):
944 951 """
945 952 Returns boolean value of a given value, represented as html element with
946 953 classes that will represent icons
947 954
948 955 :param value: given value to convert to html node
949 956 """
950 957
951 958 if value: # does bool conversion
952 959 return HTML.tag('i', class_="icon-true")
953 960 else: # not true as bool
954 961 if show_at_false:
955 962 return HTML.tag('i', class_="icon-false")
956 963 return HTML.tag('i')
957 964
958 965 #==============================================================================
959 966 # PERMS
960 967 #==============================================================================
961 968 from rhodecode.lib.auth import HasPermissionAny, HasPermissionAll, \
962 969 HasRepoPermissionAny, HasRepoPermissionAll, HasRepoGroupPermissionAll, \
963 970 HasRepoGroupPermissionAny, HasRepoPermissionAnyApi, get_csrf_token, \
964 971 csrf_token_key
965 972
966 973
967 974 #==============================================================================
968 975 # GRAVATAR URL
969 976 #==============================================================================
970 977 class InitialsGravatar(object):
971 978 def __init__(self, email_address, first_name, last_name, size=30,
972 979 background=None, text_color='#fff'):
973 980 self.size = size
974 981 self.first_name = first_name
975 982 self.last_name = last_name
976 983 self.email_address = email_address
977 984 self.background = background or self.str2color(email_address)
978 985 self.text_color = text_color
979 986
980 987 def get_color_bank(self):
981 988 """
982 989 returns a predefined list of colors that gravatars can use.
983 990 Those are randomized distinct colors that guarantee readability and
984 991 uniqueness.
985 992
986 993 generated with: http://phrogz.net/css/distinct-colors.html
987 994 """
988 995 return [
989 996 '#bf3030', '#a67f53', '#00ff00', '#5989b3', '#392040', '#d90000',
990 997 '#402910', '#204020', '#79baf2', '#a700b3', '#bf6060', '#7f5320',
991 998 '#008000', '#003059', '#ee00ff', '#ff0000', '#8c4b00', '#007300',
992 999 '#005fb3', '#de73e6', '#ff4040', '#ffaa00', '#3df255', '#203140',
993 1000 '#47004d', '#591616', '#664400', '#59b365', '#0d2133', '#83008c',
994 1001 '#592d2d', '#bf9f60', '#73e682', '#1d3f73', '#73006b', '#402020',
995 1002 '#b2862d', '#397341', '#597db3', '#e600d6', '#a60000', '#736039',
996 1003 '#00b318', '#79aaf2', '#330d30', '#ff8080', '#403010', '#16591f',
997 1004 '#002459', '#8c4688', '#e50000', '#ffbf40', '#00732e', '#102340',
998 1005 '#bf60ac', '#8c4646', '#cc8800', '#00a642', '#1d3473', '#b32d98',
999 1006 '#660e00', '#ffd580', '#80ffb2', '#7391e6', '#733967', '#d97b6c',
1000 1007 '#8c5e00', '#59b389', '#3967e6', '#590047', '#73281d', '#665200',
1001 1008 '#00e67a', '#2d50b3', '#8c2377', '#734139', '#b2982d', '#16593a',
1002 1009 '#001859', '#ff00aa', '#a65e53', '#ffcc00', '#0d3321', '#2d3959',
1003 1010 '#731d56', '#401610', '#4c3d00', '#468c6c', '#002ca6', '#d936a3',
1004 1011 '#d94c36', '#403920', '#36d9a3', '#0d1733', '#592d4a', '#993626',
1005 1012 '#cca300', '#00734d', '#46598c', '#8c005e', '#7f1100', '#8c7000',
1006 1013 '#00a66f', '#7382e6', '#b32d74', '#d9896c', '#ffe680', '#1d7362',
1007 1014 '#364cd9', '#73003d', '#d93a00', '#998a4d', '#59b3a1', '#5965b3',
1008 1015 '#e5007a', '#73341d', '#665f00', '#00b38f', '#0018b3', '#59163a',
1009 1016 '#b2502d', '#bfb960', '#00ffcc', '#23318c', '#a6537f', '#734939',
1010 1017 '#b2a700', '#104036', '#3d3df2', '#402031', '#e56739', '#736f39',
1011 1018 '#79f2ea', '#000059', '#401029', '#4c1400', '#ffee00', '#005953',
1012 1019 '#101040', '#990052', '#402820', '#403d10', '#00ffee', '#0000d9',
1013 1020 '#ff80c4', '#a66953', '#eeff00', '#00ccbe', '#8080ff', '#e673a1',
1014 1021 '#a62c00', '#474d00', '#1a3331', '#46468c', '#733950', '#662900',
1015 1022 '#858c23', '#238c85', '#0f0073', '#b20047', '#d9986c', '#becc00',
1016 1023 '#396f73', '#281d73', '#ff0066', '#ff6600', '#dee673', '#59adb3',
1017 1024 '#6559b3', '#590024', '#b2622d', '#98b32d', '#36ced9', '#332d59',
1018 1025 '#40001a', '#733f1d', '#526600', '#005359', '#242040', '#bf6079',
1019 1026 '#735039', '#cef23d', '#007780', '#5630bf', '#66001b', '#b24700',
1020 1027 '#acbf60', '#1d6273', '#25008c', '#731d34', '#a67453', '#50592d',
1021 1028 '#00ccff', '#6600ff', '#ff0044', '#4c1f00', '#8a994d', '#79daf2',
1022 1029 '#a173e6', '#d93662', '#402310', '#aaff00', '#2d98b3', '#8c40ff',
1023 1030 '#592d39', '#ff8c40', '#354020', '#103640', '#1a0040', '#331a20',
1024 1031 '#331400', '#334d00', '#1d5673', '#583973', '#7f0022', '#4c3626',
1025 1032 '#88cc00', '#36a3d9', '#3d0073', '#d9364c', '#33241a', '#698c23',
1026 1033 '#5995b3', '#300059', '#e57382', '#7f3300', '#366600', '#00aaff',
1027 1034 '#3a1659', '#733941', '#663600', '#74b32d', '#003c59', '#7f53a6',
1028 1035 '#73000f', '#ff8800', '#baf279', '#79caf2', '#291040', '#a6293a',
1029 1036 '#b2742d', '#587339', '#0077b3', '#632699', '#400009', '#d9a66c',
1030 1037 '#294010', '#2d4a59', '#aa00ff', '#4c131b', '#b25f00', '#5ce600',
1031 1038 '#267399', '#a336d9', '#990014', '#664e33', '#86bf60', '#0088ff',
1032 1039 '#7700b3', '#593a16', '#073300', '#1d4b73', '#ac60bf', '#e59539',
1033 1040 '#4f8c46', '#368dd9', '#5c0073'
1034 1041 ]
1035 1042
1036 1043 def rgb_to_hex_color(self, rgb_tuple):
1037 1044 """
1038 1045 Converts an rgb_tuple passed to an hex color.
1039 1046
1040 1047 :param rgb_tuple: tuple with 3 ints represents rgb color space
1041 1048 """
1042 1049 return '#' + ("".join(map(chr, rgb_tuple)).encode('hex'))
1043 1050
1044 1051 def email_to_int_list(self, email_str):
1045 1052 """
1046 1053 Get every byte of the hex digest value of email and turn it to integer.
1047 1054 It's going to be always between 0-255
1048 1055 """
1049 1056 digest = md5_safe(email_str.lower())
1050 1057 return [int(digest[i * 2:i * 2 + 2], 16) for i in range(16)]
1051 1058
1052 1059 def pick_color_bank_index(self, email_str, color_bank):
1053 1060 return self.email_to_int_list(email_str)[0] % len(color_bank)
1054 1061
1055 1062 def str2color(self, email_str):
1056 1063 """
1057 1064 Tries to map in a stable algorithm an email to color
1058 1065
1059 1066 :param email_str:
1060 1067 """
1061 1068 color_bank = self.get_color_bank()
1062 1069 # pick position (module it's length so we always find it in the
1063 1070 # bank even if it's smaller than 256 values
1064 1071 pos = self.pick_color_bank_index(email_str, color_bank)
1065 1072 return color_bank[pos]
1066 1073
1067 1074 def normalize_email(self, email_address):
1068 1075 import unicodedata
1069 1076 # default host used to fill in the fake/missing email
1070 1077 default_host = u'localhost'
1071 1078
1072 1079 if not email_address:
1073 1080 email_address = u'%s@%s' % (User.DEFAULT_USER, default_host)
1074 1081
1075 1082 email_address = safe_unicode(email_address)
1076 1083
1077 1084 if u'@' not in email_address:
1078 1085 email_address = u'%s@%s' % (email_address, default_host)
1079 1086
1080 1087 if email_address.endswith(u'@'):
1081 1088 email_address = u'%s%s' % (email_address, default_host)
1082 1089
1083 1090 email_address = unicodedata.normalize('NFKD', email_address)\
1084 1091 .encode('ascii', 'ignore')
1085 1092 return email_address
1086 1093
1087 1094 def get_initials(self):
1088 1095 """
1089 1096 Returns 2 letter initials calculated based on the input.
1090 1097 The algorithm picks first given email address, and takes first letter
1091 1098 of part before @, and then the first letter of server name. In case
1092 1099 the part before @ is in a format of `somestring.somestring2` it replaces
1093 1100 the server letter with first letter of somestring2
1094 1101
1095 1102 In case function was initialized with both first and lastname, this
1096 1103 overrides the extraction from email by first letter of the first and
1097 1104 last name. We add special logic to that functionality, In case Full name
1098 1105 is compound, like Guido Von Rossum, we use last part of the last name
1099 1106 (Von Rossum) picking `R`.
1100 1107
1101 1108 Function also normalizes the non-ascii characters to they ascii
1102 1109 representation, eg Ą => A
1103 1110 """
1104 1111 import unicodedata
1105 1112 # replace non-ascii to ascii
1106 1113 first_name = unicodedata.normalize(
1107 1114 'NFKD', safe_unicode(self.first_name)).encode('ascii', 'ignore')
1108 1115 last_name = unicodedata.normalize(
1109 1116 'NFKD', safe_unicode(self.last_name)).encode('ascii', 'ignore')
1110 1117
1111 1118 # do NFKD encoding, and also make sure email has proper format
1112 1119 email_address = self.normalize_email(self.email_address)
1113 1120
1114 1121 # first push the email initials
1115 1122 prefix, server = email_address.split('@', 1)
1116 1123
1117 1124 # check if prefix is maybe a 'first_name.last_name' syntax
1118 1125 _dot_split = prefix.rsplit('.', 1)
1119 1126 if len(_dot_split) == 2 and _dot_split[1]:
1120 1127 initials = [_dot_split[0][0], _dot_split[1][0]]
1121 1128 else:
1122 1129 initials = [prefix[0], server[0]]
1123 1130
1124 1131 # then try to replace either first_name or last_name
1125 1132 fn_letter = (first_name or " ")[0].strip()
1126 1133 ln_letter = (last_name.split(' ', 1)[-1] or " ")[0].strip()
1127 1134
1128 1135 if fn_letter:
1129 1136 initials[0] = fn_letter
1130 1137
1131 1138 if ln_letter:
1132 1139 initials[1] = ln_letter
1133 1140
1134 1141 return ''.join(initials).upper()
1135 1142
1136 1143 def get_img_data_by_type(self, font_family, img_type):
1137 1144 default_user = """
1138 1145 <svg xmlns="http://www.w3.org/2000/svg"
1139 1146 version="1.1" x="0px" y="0px" width="{size}" height="{size}"
1140 1147 viewBox="-15 -10 439.165 429.164"
1141 1148
1142 1149 xml:space="preserve"
1143 1150 style="background:{background};" >
1144 1151
1145 1152 <path d="M204.583,216.671c50.664,0,91.74-48.075,
1146 1153 91.74-107.378c0-82.237-41.074-107.377-91.74-107.377
1147 1154 c-50.668,0-91.74,25.14-91.74,107.377C112.844,
1148 1155 168.596,153.916,216.671,
1149 1156 204.583,216.671z" fill="{text_color}"/>
1150 1157 <path d="M407.164,374.717L360.88,
1151 1158 270.454c-2.117-4.771-5.836-8.728-10.465-11.138l-71.83-37.392
1152 1159 c-1.584-0.823-3.502-0.663-4.926,0.415c-20.316,
1153 1160 15.366-44.203,23.488-69.076,23.488c-24.877,
1154 1161 0-48.762-8.122-69.078-23.488
1155 1162 c-1.428-1.078-3.346-1.238-4.93-0.415L58.75,
1156 1163 259.316c-4.631,2.41-8.346,6.365-10.465,11.138L2.001,374.717
1157 1164 c-3.191,7.188-2.537,15.412,1.75,22.005c4.285,
1158 1165 6.592,11.537,10.526,19.4,10.526h362.861c7.863,0,15.117-3.936,
1159 1166 19.402-10.527 C409.699,390.129,
1160 1167 410.355,381.902,407.164,374.717z" fill="{text_color}"/>
1161 1168 </svg>""".format(
1162 1169 size=self.size,
1163 1170 background='#979797', # @grey4
1164 1171 text_color=self.text_color,
1165 1172 font_family=font_family)
1166 1173
1167 1174 return {
1168 1175 "default_user": default_user
1169 1176 }[img_type]
1170 1177
1171 1178 def get_img_data(self, svg_type=None):
1172 1179 """
1173 1180 generates the svg metadata for image
1174 1181 """
1175 1182 fonts = [
1176 1183 '-apple-system',
1177 1184 'BlinkMacSystemFont',
1178 1185 'Segoe UI',
1179 1186 'Roboto',
1180 1187 'Oxygen-Sans',
1181 1188 'Ubuntu',
1182 1189 'Cantarell',
1183 1190 'Helvetica Neue',
1184 1191 'sans-serif'
1185 1192 ]
1186 1193 font_family = ','.join(fonts)
1187 1194 if svg_type:
1188 1195 return self.get_img_data_by_type(font_family, svg_type)
1189 1196
1190 1197 initials = self.get_initials()
1191 1198 img_data = """
1192 1199 <svg xmlns="http://www.w3.org/2000/svg" pointer-events="none"
1193 1200 width="{size}" height="{size}"
1194 1201 style="width: 100%; height: 100%; background-color: {background}"
1195 1202 viewBox="0 0 {size} {size}">
1196 1203 <text text-anchor="middle" y="50%" x="50%" dy="0.35em"
1197 1204 pointer-events="auto" fill="{text_color}"
1198 1205 font-family="{font_family}"
1199 1206 style="font-weight: 400; font-size: {f_size}px;">{text}
1200 1207 </text>
1201 1208 </svg>""".format(
1202 1209 size=self.size,
1203 1210 f_size=self.size/2.05, # scale the text inside the box nicely
1204 1211 background=self.background,
1205 1212 text_color=self.text_color,
1206 1213 text=initials.upper(),
1207 1214 font_family=font_family)
1208 1215
1209 1216 return img_data
1210 1217
1211 1218 def generate_svg(self, svg_type=None):
1212 1219 img_data = self.get_img_data(svg_type)
1213 1220 return "data:image/svg+xml;base64,%s" % img_data.encode('base64')
1214 1221
1215 1222
1216 1223 def initials_gravatar(email_address, first_name, last_name, size=30):
1217 1224 svg_type = None
1218 1225 if email_address == User.DEFAULT_USER_EMAIL:
1219 1226 svg_type = 'default_user'
1220 1227 klass = InitialsGravatar(email_address, first_name, last_name, size)
1221 1228 return klass.generate_svg(svg_type=svg_type)
1222 1229
1223 1230
1224 1231 def gravatar_url(email_address, size=30, request=None):
1225 1232 request = get_current_request()
1226 1233 _use_gravatar = request.call_context.visual.use_gravatar
1227 1234 _gravatar_url = request.call_context.visual.gravatar_url
1228 1235
1229 1236 _gravatar_url = _gravatar_url or User.DEFAULT_GRAVATAR_URL
1230 1237
1231 1238 email_address = email_address or User.DEFAULT_USER_EMAIL
1232 1239 if isinstance(email_address, unicode):
1233 1240 # hashlib crashes on unicode items
1234 1241 email_address = safe_str(email_address)
1235 1242
1236 1243 # empty email or default user
1237 1244 if not email_address or email_address == User.DEFAULT_USER_EMAIL:
1238 1245 return initials_gravatar(User.DEFAULT_USER_EMAIL, '', '', size=size)
1239 1246
1240 1247 if _use_gravatar:
1241 1248 # TODO: Disuse pyramid thread locals. Think about another solution to
1242 1249 # get the host and schema here.
1243 1250 request = get_current_request()
1244 1251 tmpl = safe_str(_gravatar_url)
1245 1252 tmpl = tmpl.replace('{email}', email_address)\
1246 1253 .replace('{md5email}', md5_safe(email_address.lower())) \
1247 1254 .replace('{netloc}', request.host)\
1248 1255 .replace('{scheme}', request.scheme)\
1249 1256 .replace('{size}', safe_str(size))
1250 1257 return tmpl
1251 1258 else:
1252 1259 return initials_gravatar(email_address, '', '', size=size)
1253 1260
1254 1261
1255 1262 class Page(_Page):
1256 1263 """
1257 1264 Custom pager to match rendering style with paginator
1258 1265 """
1259 1266
1260 1267 def _get_pos(self, cur_page, max_page, items):
1261 1268 edge = (items / 2) + 1
1262 1269 if (cur_page <= edge):
1263 1270 radius = max(items / 2, items - cur_page)
1264 1271 elif (max_page - cur_page) < edge:
1265 1272 radius = (items - 1) - (max_page - cur_page)
1266 1273 else:
1267 1274 radius = items / 2
1268 1275
1269 1276 left = max(1, (cur_page - (radius)))
1270 1277 right = min(max_page, cur_page + (radius))
1271 1278 return left, cur_page, right
1272 1279
1273 1280 def _range(self, regexp_match):
1274 1281 """
1275 1282 Return range of linked pages (e.g. '1 2 [3] 4 5 6 7 8').
1276 1283
1277 1284 Arguments:
1278 1285
1279 1286 regexp_match
1280 1287 A "re" (regular expressions) match object containing the
1281 1288 radius of linked pages around the current page in
1282 1289 regexp_match.group(1) as a string
1283 1290
1284 1291 This function is supposed to be called as a callable in
1285 1292 re.sub.
1286 1293
1287 1294 """
1288 1295 radius = int(regexp_match.group(1))
1289 1296
1290 1297 # Compute the first and last page number within the radius
1291 1298 # e.g. '1 .. 5 6 [7] 8 9 .. 12'
1292 1299 # -> leftmost_page = 5
1293 1300 # -> rightmost_page = 9
1294 1301 leftmost_page, _cur, rightmost_page = self._get_pos(self.page,
1295 1302 self.last_page,
1296 1303 (radius * 2) + 1)
1297 1304 nav_items = []
1298 1305
1299 1306 # Create a link to the first page (unless we are on the first page
1300 1307 # or there would be no need to insert '..' spacers)
1301 1308 if self.page != self.first_page and self.first_page < leftmost_page:
1302 1309 nav_items.append(self._pagerlink(self.first_page, self.first_page))
1303 1310
1304 1311 # Insert dots if there are pages between the first page
1305 1312 # and the currently displayed page range
1306 1313 if leftmost_page - self.first_page > 1:
1307 1314 # Wrap in a SPAN tag if nolink_attr is set
1308 1315 text = '..'
1309 1316 if self.dotdot_attr:
1310 1317 text = HTML.span(c=text, **self.dotdot_attr)
1311 1318 nav_items.append(text)
1312 1319
1313 1320 for thispage in xrange(leftmost_page, rightmost_page + 1):
1314 1321 # Hilight the current page number and do not use a link
1315 1322 if thispage == self.page:
1316 1323 text = '%s' % (thispage,)
1317 1324 # Wrap in a SPAN tag if nolink_attr is set
1318 1325 if self.curpage_attr:
1319 1326 text = HTML.span(c=text, **self.curpage_attr)
1320 1327 nav_items.append(text)
1321 1328 # Otherwise create just a link to that page
1322 1329 else:
1323 1330 text = '%s' % (thispage,)
1324 1331 nav_items.append(self._pagerlink(thispage, text))
1325 1332
1326 1333 # Insert dots if there are pages between the displayed
1327 1334 # page numbers and the end of the page range
1328 1335 if self.last_page - rightmost_page > 1:
1329 1336 text = '..'
1330 1337 # Wrap in a SPAN tag if nolink_attr is set
1331 1338 if self.dotdot_attr:
1332 1339 text = HTML.span(c=text, **self.dotdot_attr)
1333 1340 nav_items.append(text)
1334 1341
1335 1342 # Create a link to the very last page (unless we are on the last
1336 1343 # page or there would be no need to insert '..' spacers)
1337 1344 if self.page != self.last_page and rightmost_page < self.last_page:
1338 1345 nav_items.append(self._pagerlink(self.last_page, self.last_page))
1339 1346
1340 1347 ## prerender links
1341 1348 #_page_link = url.current()
1342 1349 #nav_items.append(literal('<link rel="prerender" href="%s?page=%s">' % (_page_link, str(int(self.page)+1))))
1343 1350 #nav_items.append(literal('<link rel="prefetch" href="%s?page=%s">' % (_page_link, str(int(self.page)+1))))
1344 1351 return self.separator.join(nav_items)
1345 1352
1346 1353 def pager(self, format='~2~', page_param='page', partial_param='partial',
1347 1354 show_if_single_page=False, separator=' ', onclick=None,
1348 1355 symbol_first='<<', symbol_last='>>',
1349 1356 symbol_previous='<', symbol_next='>',
1350 1357 link_attr={'class': 'pager_link', 'rel': 'prerender'},
1351 1358 curpage_attr={'class': 'pager_curpage'},
1352 1359 dotdot_attr={'class': 'pager_dotdot'}, **kwargs):
1353 1360
1354 1361 self.curpage_attr = curpage_attr
1355 1362 self.separator = separator
1356 1363 self.pager_kwargs = kwargs
1357 1364 self.page_param = page_param
1358 1365 self.partial_param = partial_param
1359 1366 self.onclick = onclick
1360 1367 self.link_attr = link_attr
1361 1368 self.dotdot_attr = dotdot_attr
1362 1369
1363 1370 # Don't show navigator if there is no more than one page
1364 1371 if self.page_count == 0 or (self.page_count == 1 and not show_if_single_page):
1365 1372 return ''
1366 1373
1367 1374 from string import Template
1368 1375 # Replace ~...~ in token format by range of pages
1369 1376 result = re.sub(r'~(\d+)~', self._range, format)
1370 1377
1371 1378 # Interpolate '%' variables
1372 1379 result = Template(result).safe_substitute({
1373 1380 'first_page': self.first_page,
1374 1381 'last_page': self.last_page,
1375 1382 'page': self.page,
1376 1383 'page_count': self.page_count,
1377 1384 'items_per_page': self.items_per_page,
1378 1385 'first_item': self.first_item,
1379 1386 'last_item': self.last_item,
1380 1387 'item_count': self.item_count,
1381 1388 'link_first': self.page > self.first_page and \
1382 1389 self._pagerlink(self.first_page, symbol_first) or '',
1383 1390 'link_last': self.page < self.last_page and \
1384 1391 self._pagerlink(self.last_page, symbol_last) or '',
1385 1392 'link_previous': self.previous_page and \
1386 1393 self._pagerlink(self.previous_page, symbol_previous) \
1387 1394 or HTML.span(symbol_previous, class_="pg-previous disabled"),
1388 1395 'link_next': self.next_page and \
1389 1396 self._pagerlink(self.next_page, symbol_next) \
1390 1397 or HTML.span(symbol_next, class_="pg-next disabled")
1391 1398 })
1392 1399
1393 1400 return literal(result)
1394 1401
1395 1402
1396 1403 #==============================================================================
1397 1404 # REPO PAGER, PAGER FOR REPOSITORY
1398 1405 #==============================================================================
1399 1406 class RepoPage(Page):
1400 1407
1401 1408 def __init__(self, collection, page=1, items_per_page=20,
1402 1409 item_count=None, url=None, **kwargs):
1403 1410
1404 1411 """Create a "RepoPage" instance. special pager for paging
1405 1412 repository
1406 1413 """
1407 1414 self._url_generator = url
1408 1415
1409 1416 # Safe the kwargs class-wide so they can be used in the pager() method
1410 1417 self.kwargs = kwargs
1411 1418
1412 1419 # Save a reference to the collection
1413 1420 self.original_collection = collection
1414 1421
1415 1422 self.collection = collection
1416 1423
1417 1424 # The self.page is the number of the current page.
1418 1425 # The first page has the number 1!
1419 1426 try:
1420 1427 self.page = int(page) # make it int() if we get it as a string
1421 1428 except (ValueError, TypeError):
1422 1429 self.page = 1
1423 1430
1424 1431 self.items_per_page = items_per_page
1425 1432
1426 1433 # Unless the user tells us how many items the collections has
1427 1434 # we calculate that ourselves.
1428 1435 if item_count is not None:
1429 1436 self.item_count = item_count
1430 1437 else:
1431 1438 self.item_count = len(self.collection)
1432 1439
1433 1440 # Compute the number of the first and last available page
1434 1441 if self.item_count > 0:
1435 1442 self.first_page = 1
1436 1443 self.page_count = int(math.ceil(float(self.item_count) /
1437 1444 self.items_per_page))
1438 1445 self.last_page = self.first_page + self.page_count - 1
1439 1446
1440 1447 # Make sure that the requested page number is the range of
1441 1448 # valid pages
1442 1449 if self.page > self.last_page:
1443 1450 self.page = self.last_page
1444 1451 elif self.page < self.first_page:
1445 1452 self.page = self.first_page
1446 1453
1447 1454 # Note: the number of items on this page can be less than
1448 1455 # items_per_page if the last page is not full
1449 1456 self.first_item = max(0, (self.item_count) - (self.page *
1450 1457 items_per_page))
1451 1458 self.last_item = ((self.item_count - 1) - items_per_page *
1452 1459 (self.page - 1))
1453 1460
1454 1461 self.items = list(self.collection[self.first_item:self.last_item + 1])
1455 1462
1456 1463 # Links to previous and next page
1457 1464 if self.page > self.first_page:
1458 1465 self.previous_page = self.page - 1
1459 1466 else:
1460 1467 self.previous_page = None
1461 1468
1462 1469 if self.page < self.last_page:
1463 1470 self.next_page = self.page + 1
1464 1471 else:
1465 1472 self.next_page = None
1466 1473
1467 1474 # No items available
1468 1475 else:
1469 1476 self.first_page = None
1470 1477 self.page_count = 0
1471 1478 self.last_page = None
1472 1479 self.first_item = None
1473 1480 self.last_item = None
1474 1481 self.previous_page = None
1475 1482 self.next_page = None
1476 1483 self.items = []
1477 1484
1478 1485 # This is a subclass of the 'list' type. Initialise the list now.
1479 1486 list.__init__(self, reversed(self.items))
1480 1487
1481 1488
1482 1489 def breadcrumb_repo_link(repo):
1483 1490 """
1484 1491 Makes a breadcrumbs path link to repo
1485 1492
1486 1493 ex::
1487 1494 group >> subgroup >> repo
1488 1495
1489 1496 :param repo: a Repository instance
1490 1497 """
1491 1498
1492 1499 path = [
1493 1500 link_to(group.name, route_path('repo_group_home', repo_group_name=group.group_name),
1494 1501 title='last change:{}'.format(format_date(group.last_commit_change)))
1495 1502 for group in repo.groups_with_parents
1496 1503 ] + [
1497 1504 link_to(repo.just_name, route_path('repo_summary', repo_name=repo.repo_name),
1498 1505 title='last change:{}'.format(format_date(repo.last_commit_change)))
1499 1506 ]
1500 1507
1501 1508 return literal(' &raquo; '.join(path))
1502 1509
1503 1510
1504 1511 def breadcrumb_repo_group_link(repo_group):
1505 1512 """
1506 1513 Makes a breadcrumbs path link to repo
1507 1514
1508 1515 ex::
1509 1516 group >> subgroup
1510 1517
1511 1518 :param repo_group: a Repository Group instance
1512 1519 """
1513 1520
1514 1521 path = [
1515 1522 link_to(group.name,
1516 1523 route_path('repo_group_home', repo_group_name=group.group_name),
1517 1524 title='last change:{}'.format(format_date(group.last_commit_change)))
1518 1525 for group in repo_group.parents
1519 1526 ] + [
1520 1527 link_to(repo_group.name,
1521 1528 route_path('repo_group_home', repo_group_name=repo_group.group_name),
1522 1529 title='last change:{}'.format(format_date(repo_group.last_commit_change)))
1523 1530 ]
1524 1531
1525 1532 return literal(' &raquo; '.join(path))
1526 1533
1527 1534
1528 1535 def format_byte_size_binary(file_size):
1529 1536 """
1530 1537 Formats file/folder sizes to standard.
1531 1538 """
1532 1539 if file_size is None:
1533 1540 file_size = 0
1534 1541
1535 1542 formatted_size = format_byte_size(file_size, binary=True)
1536 1543 return formatted_size
1537 1544
1538 1545
1539 1546 def urlify_text(text_, safe=True):
1540 1547 """
1541 1548 Extrac urls from text and make html links out of them
1542 1549
1543 1550 :param text_:
1544 1551 """
1545 1552
1546 1553 url_pat = re.compile(r'''(http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@#.&+]'''
1547 1554 '''|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+)''')
1548 1555
1549 1556 def url_func(match_obj):
1550 1557 url_full = match_obj.groups()[0]
1551 1558 return '<a href="%(url)s">%(url)s</a>' % ({'url': url_full})
1552 1559 _newtext = url_pat.sub(url_func, text_)
1553 1560 if safe:
1554 1561 return literal(_newtext)
1555 1562 return _newtext
1556 1563
1557 1564
1558 1565 def urlify_commits(text_, repository):
1559 1566 """
1560 1567 Extract commit ids from text and make link from them
1561 1568
1562 1569 :param text_:
1563 1570 :param repository: repo name to build the URL with
1564 1571 """
1565 1572
1566 1573 URL_PAT = re.compile(r'(^|\s)([0-9a-fA-F]{12,40})($|\s)')
1567 1574
1568 1575 def url_func(match_obj):
1569 1576 commit_id = match_obj.groups()[1]
1570 1577 pref = match_obj.groups()[0]
1571 1578 suf = match_obj.groups()[2]
1572 1579
1573 1580 tmpl = (
1574 1581 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1575 1582 '%(commit_id)s</a>%(suf)s'
1576 1583 )
1577 1584 return tmpl % {
1578 1585 'pref': pref,
1579 1586 'cls': 'revision-link',
1580 1587 'url': route_url('repo_commit', repo_name=repository, commit_id=commit_id),
1581 1588 'commit_id': commit_id,
1582 1589 'suf': suf
1583 1590 }
1584 1591
1585 1592 newtext = URL_PAT.sub(url_func, text_)
1586 1593
1587 1594 return newtext
1588 1595
1589 1596
1590 1597 def _process_url_func(match_obj, repo_name, uid, entry,
1591 1598 return_raw_data=False, link_format='html'):
1592 1599 pref = ''
1593 1600 if match_obj.group().startswith(' '):
1594 1601 pref = ' '
1595 1602
1596 1603 issue_id = ''.join(match_obj.groups())
1597 1604
1598 1605 if link_format == 'html':
1599 1606 tmpl = (
1600 1607 '%(pref)s<a class="%(cls)s" href="%(url)s">'
1601 1608 '%(issue-prefix)s%(id-repr)s'
1602 1609 '</a>')
1603 1610 elif link_format == 'rst':
1604 1611 tmpl = '`%(issue-prefix)s%(id-repr)s <%(url)s>`_'
1605 1612 elif link_format == 'markdown':
1606 1613 tmpl = '[%(issue-prefix)s%(id-repr)s](%(url)s)'
1607 1614 else:
1608 1615 raise ValueError('Bad link_format:{}'.format(link_format))
1609 1616
1610 1617 (repo_name_cleaned,
1611 1618 parent_group_name) = RepoGroupModel()._get_group_name_and_parent(repo_name)
1612 1619
1613 1620 # variables replacement
1614 1621 named_vars = {
1615 1622 'id': issue_id,
1616 1623 'repo': repo_name,
1617 1624 'repo_name': repo_name_cleaned,
1618 1625 'group_name': parent_group_name
1619 1626 }
1620 1627 # named regex variables
1621 1628 named_vars.update(match_obj.groupdict())
1622 1629 _url = string.Template(entry['url']).safe_substitute(**named_vars)
1623 1630
1624 1631 def quote_cleaner(input_str):
1625 1632 """Remove quotes as it's HTML"""
1626 1633 return input_str.replace('"', '')
1627 1634
1628 1635 data = {
1629 1636 'pref': pref,
1630 1637 'cls': quote_cleaner('issue-tracker-link'),
1631 1638 'url': quote_cleaner(_url),
1632 1639 'id-repr': issue_id,
1633 1640 'issue-prefix': entry['pref'],
1634 1641 'serv': entry['url'],
1635 1642 }
1636 1643 if return_raw_data:
1637 1644 return {
1638 1645 'id': issue_id,
1639 1646 'url': _url
1640 1647 }
1641 1648 return tmpl % data
1642 1649
1643 1650
1644 1651 def get_active_pattern_entries(repo_name):
1645 1652 repo = None
1646 1653 if repo_name:
1647 1654 # Retrieving repo_name to avoid invalid repo_name to explode on
1648 1655 # IssueTrackerSettingsModel but still passing invalid name further down
1649 1656 repo = Repository.get_by_repo_name(repo_name, cache=True)
1650 1657
1651 1658 settings_model = IssueTrackerSettingsModel(repo=repo)
1652 1659 active_entries = settings_model.get_settings(cache=True)
1653 1660 return active_entries
1654 1661
1655 1662
1656 1663 def process_patterns(text_string, repo_name, link_format='html', active_entries=None):
1657 1664
1658 1665 allowed_formats = ['html', 'rst', 'markdown']
1659 1666 if link_format not in allowed_formats:
1660 1667 raise ValueError('Link format can be only one of:{} got {}'.format(
1661 1668 allowed_formats, link_format))
1662 1669
1663 1670 active_entries = active_entries or get_active_pattern_entries(repo_name)
1664 1671 issues_data = []
1665 1672 newtext = text_string
1666 1673
1667 1674 for uid, entry in active_entries.items():
1668 1675 log.debug('found issue tracker entry with uid %s', uid)
1669 1676
1670 1677 if not (entry['pat'] and entry['url']):
1671 1678 log.debug('skipping due to missing data')
1672 1679 continue
1673 1680
1674 1681 log.debug('issue tracker entry: uid: `%s` PAT:%s URL:%s PREFIX:%s',
1675 1682 uid, entry['pat'], entry['url'], entry['pref'])
1676 1683
1677 1684 try:
1678 1685 pattern = re.compile(r'%s' % entry['pat'])
1679 1686 except re.error:
1680 1687 log.exception(
1681 1688 'issue tracker pattern: `%s` failed to compile',
1682 1689 entry['pat'])
1683 1690 continue
1684 1691
1685 1692 data_func = partial(
1686 1693 _process_url_func, repo_name=repo_name, entry=entry, uid=uid,
1687 1694 return_raw_data=True)
1688 1695
1689 1696 for match_obj in pattern.finditer(text_string):
1690 1697 issues_data.append(data_func(match_obj))
1691 1698
1692 1699 url_func = partial(
1693 1700 _process_url_func, repo_name=repo_name, entry=entry, uid=uid,
1694 1701 link_format=link_format)
1695 1702
1696 1703 newtext = pattern.sub(url_func, newtext)
1697 1704 log.debug('processed prefix:uid `%s`', uid)
1698 1705
1699 1706 return newtext, issues_data
1700 1707
1701 1708
1702 1709 def urlify_commit_message(commit_text, repository=None, active_pattern_entries=None):
1703 1710 """
1704 1711 Parses given text message and makes proper links.
1705 1712 issues are linked to given issue-server, and rest is a commit link
1706 1713
1707 1714 :param commit_text:
1708 1715 :param repository:
1709 1716 """
1710 1717 def escaper(string):
1711 1718 return string.replace('<', '&lt;').replace('>', '&gt;')
1712 1719
1713 1720 newtext = escaper(commit_text)
1714 1721
1715 1722 # extract http/https links and make them real urls
1716 1723 newtext = urlify_text(newtext, safe=False)
1717 1724
1718 1725 # urlify commits - extract commit ids and make link out of them, if we have
1719 1726 # the scope of repository present.
1720 1727 if repository:
1721 1728 newtext = urlify_commits(newtext, repository)
1722 1729
1723 1730 # process issue tracker patterns
1724 1731 newtext, issues = process_patterns(newtext, repository or '',
1725 1732 active_entries=active_pattern_entries)
1726 1733
1727 1734 return literal(newtext)
1728 1735
1729 1736
1730 1737 def render_binary(repo_name, file_obj):
1731 1738 """
1732 1739 Choose how to render a binary file
1733 1740 """
1734 1741
1735 1742 filename = file_obj.name
1736 1743
1737 1744 # images
1738 1745 for ext in ['*.png', '*.jpg', '*.ico', '*.gif']:
1739 1746 if fnmatch.fnmatch(filename, pat=ext):
1740 1747 alt = escape(filename)
1741 1748 src = route_path(
1742 1749 'repo_file_raw', repo_name=repo_name,
1743 1750 commit_id=file_obj.commit.raw_id,
1744 1751 f_path=file_obj.path)
1745 1752 return literal(
1746 1753 '<img class="rendered-binary" alt="{}" src="{}">'.format(alt, src))
1747 1754
1748 1755
1749 1756 def renderer_from_filename(filename, exclude=None):
1750 1757 """
1751 1758 choose a renderer based on filename, this works only for text based files
1752 1759 """
1753 1760
1754 1761 # ipython
1755 1762 for ext in ['*.ipynb']:
1756 1763 if fnmatch.fnmatch(filename, pat=ext):
1757 1764 return 'jupyter'
1758 1765
1759 1766 is_markup = MarkupRenderer.renderer_from_filename(filename, exclude=exclude)
1760 1767 if is_markup:
1761 1768 return is_markup
1762 1769 return None
1763 1770
1764 1771
1765 1772 def render(source, renderer='rst', mentions=False, relative_urls=None,
1766 1773 repo_name=None):
1767 1774
1768 1775 def maybe_convert_relative_links(html_source):
1769 1776 if relative_urls:
1770 1777 return relative_links(html_source, relative_urls)
1771 1778 return html_source
1772 1779
1773 1780 if renderer == 'plain':
1774 1781 return literal(
1775 1782 MarkupRenderer.plain(source, leading_newline=False))
1776 1783
1777 1784 elif renderer == 'rst':
1778 1785 if repo_name:
1779 1786 # process patterns on comments if we pass in repo name
1780 1787 source, issues = process_patterns(
1781 1788 source, repo_name, link_format='rst')
1782 1789
1783 1790 return literal(
1784 1791 '<div class="rst-block">%s</div>' %
1785 1792 maybe_convert_relative_links(
1786 1793 MarkupRenderer.rst(source, mentions=mentions)))
1787 1794
1788 1795 elif renderer == 'markdown':
1789 1796 if repo_name:
1790 1797 # process patterns on comments if we pass in repo name
1791 1798 source, issues = process_patterns(
1792 1799 source, repo_name, link_format='markdown')
1793 1800
1794 1801 return literal(
1795 1802 '<div class="markdown-block">%s</div>' %
1796 1803 maybe_convert_relative_links(
1797 1804 MarkupRenderer.markdown(source, flavored=True,
1798 1805 mentions=mentions)))
1799 1806
1800 1807 elif renderer == 'jupyter':
1801 1808 return literal(
1802 1809 '<div class="ipynb">%s</div>' %
1803 1810 maybe_convert_relative_links(
1804 1811 MarkupRenderer.jupyter(source)))
1805 1812
1806 1813 # None means just show the file-source
1807 1814 return None
1808 1815
1809 1816
1810 1817 def commit_status(repo, commit_id):
1811 1818 return ChangesetStatusModel().get_status(repo, commit_id)
1812 1819
1813 1820
1814 1821 def commit_status_lbl(commit_status):
1815 1822 return dict(ChangesetStatus.STATUSES).get(commit_status)
1816 1823
1817 1824
1818 1825 def commit_time(repo_name, commit_id):
1819 1826 repo = Repository.get_by_repo_name(repo_name)
1820 1827 commit = repo.get_commit(commit_id=commit_id)
1821 1828 return commit.date
1822 1829
1823 1830
1824 1831 def get_permission_name(key):
1825 1832 return dict(Permission.PERMS).get(key)
1826 1833
1827 1834
1828 1835 def journal_filter_help(request):
1829 1836 _ = request.translate
1830 1837 from rhodecode.lib.audit_logger import ACTIONS
1831 1838 actions = '\n'.join(textwrap.wrap(', '.join(sorted(ACTIONS.keys())), 80))
1832 1839
1833 1840 return _(
1834 1841 'Example filter terms:\n' +
1835 1842 ' repository:vcs\n' +
1836 1843 ' username:marcin\n' +
1837 1844 ' username:(NOT marcin)\n' +
1838 1845 ' action:*push*\n' +
1839 1846 ' ip:127.0.0.1\n' +
1840 1847 ' date:20120101\n' +
1841 1848 ' date:[20120101100000 TO 20120102]\n' +
1842 1849 '\n' +
1843 1850 'Actions: {actions}\n' +
1844 1851 '\n' +
1845 1852 'Generate wildcards using \'*\' character:\n' +
1846 1853 ' "repository:vcs*" - search everything starting with \'vcs\'\n' +
1847 1854 ' "repository:*vcs*" - search for repository containing \'vcs\'\n' +
1848 1855 '\n' +
1849 1856 'Optional AND / OR operators in queries\n' +
1850 1857 ' "repository:vcs OR repository:test"\n' +
1851 1858 ' "username:test AND repository:test*"\n'
1852 1859 ).format(actions=actions)
1853 1860
1854 1861
1855 1862 def not_mapped_error(repo_name):
1856 1863 from rhodecode.translation import _
1857 1864 flash(_('%s repository is not mapped to db perhaps'
1858 1865 ' it was created or renamed from the filesystem'
1859 1866 ' please run the application again'
1860 1867 ' in order to rescan repositories') % repo_name, category='error')
1861 1868
1862 1869
1863 1870 def ip_range(ip_addr):
1864 1871 from rhodecode.model.db import UserIpMap
1865 1872 s, e = UserIpMap._get_ip_range(ip_addr)
1866 1873 return '%s - %s' % (s, e)
1867 1874
1868 1875
1869 1876 def form(url, method='post', needs_csrf_token=True, **attrs):
1870 1877 """Wrapper around webhelpers.tags.form to prevent CSRF attacks."""
1871 1878 if method.lower() != 'get' and needs_csrf_token:
1872 1879 raise Exception(
1873 1880 'Forms to POST/PUT/DELETE endpoints should have (in general) a ' +
1874 1881 'CSRF token. If the endpoint does not require such token you can ' +
1875 1882 'explicitly set the parameter needs_csrf_token to false.')
1876 1883
1877 1884 return wh_form(url, method=method, **attrs)
1878 1885
1879 1886
1880 1887 def secure_form(form_url, method="POST", multipart=False, **attrs):
1881 1888 """Start a form tag that points the action to an url. This
1882 1889 form tag will also include the hidden field containing
1883 1890 the auth token.
1884 1891
1885 1892 The url options should be given either as a string, or as a
1886 1893 ``url()`` function. The method for the form defaults to POST.
1887 1894
1888 1895 Options:
1889 1896
1890 1897 ``multipart``
1891 1898 If set to True, the enctype is set to "multipart/form-data".
1892 1899 ``method``
1893 1900 The method to use when submitting the form, usually either
1894 1901 "GET" or "POST". If "PUT", "DELETE", or another verb is used, a
1895 1902 hidden input with name _method is added to simulate the verb
1896 1903 over POST.
1897 1904
1898 1905 """
1899 1906 from webhelpers.pylonslib.secure_form import insecure_form
1900 1907
1901 1908 if 'request' in attrs:
1902 1909 session = attrs['request'].session
1903 1910 del attrs['request']
1904 1911 else:
1905 1912 raise ValueError(
1906 1913 'Calling this form requires request= to be passed as argument')
1907 1914
1908 1915 form = insecure_form(form_url, method, multipart, **attrs)
1909 1916 token = literal(
1910 1917 '<input type="hidden" id="{}" name="{}" value="{}">'.format(
1911 1918 csrf_token_key, csrf_token_key, get_csrf_token(session)))
1912 1919
1913 1920 return literal("%s\n%s" % (form, token))
1914 1921
1915 1922
1916 1923 def dropdownmenu(name, selected, options, enable_filter=False, **attrs):
1917 1924 select_html = select(name, selected, options, **attrs)
1918 1925 select2 = """
1919 1926 <script>
1920 1927 $(document).ready(function() {
1921 1928 $('#%s').select2({
1922 1929 containerCssClass: 'drop-menu',
1923 1930 dropdownCssClass: 'drop-menu-dropdown',
1924 1931 dropdownAutoWidth: true%s
1925 1932 });
1926 1933 });
1927 1934 </script>
1928 1935 """
1929 1936 filter_option = """,
1930 1937 minimumResultsForSearch: -1
1931 1938 """
1932 1939 input_id = attrs.get('id') or name
1933 1940 filter_enabled = "" if enable_filter else filter_option
1934 1941 select_script = literal(select2 % (input_id, filter_enabled))
1935 1942
1936 1943 return literal(select_html+select_script)
1937 1944
1938 1945
1939 1946 def get_visual_attr(tmpl_context_var, attr_name):
1940 1947 """
1941 1948 A safe way to get a variable from visual variable of template context
1942 1949
1943 1950 :param tmpl_context_var: instance of tmpl_context, usually present as `c`
1944 1951 :param attr_name: name of the attribute we fetch from the c.visual
1945 1952 """
1946 1953 visual = getattr(tmpl_context_var, 'visual', None)
1947 1954 if not visual:
1948 1955 return
1949 1956 else:
1950 1957 return getattr(visual, attr_name, None)
1951 1958
1952 1959
1953 1960 def get_last_path_part(file_node):
1954 1961 if not file_node.path:
1955 1962 return u'/'
1956 1963
1957 1964 path = safe_unicode(file_node.path.split('/')[-1])
1958 1965 return u'../' + path
1959 1966
1960 1967
1961 1968 def route_url(*args, **kwargs):
1962 1969 """
1963 1970 Wrapper around pyramids `route_url` (fully qualified url) function.
1964 1971 """
1965 1972 req = get_current_request()
1966 1973 return req.route_url(*args, **kwargs)
1967 1974
1968 1975
1969 1976 def route_path(*args, **kwargs):
1970 1977 """
1971 1978 Wrapper around pyramids `route_path` function.
1972 1979 """
1973 1980 req = get_current_request()
1974 1981 return req.route_path(*args, **kwargs)
1975 1982
1976 1983
1977 1984 def route_path_or_none(*args, **kwargs):
1978 1985 try:
1979 1986 return route_path(*args, **kwargs)
1980 1987 except KeyError:
1981 1988 return None
1982 1989
1983 1990
1984 1991 def current_route_path(request, **kw):
1985 1992 new_args = request.GET.mixed()
1986 1993 new_args.update(kw)
1987 1994 return request.current_route_path(_query=new_args)
1988 1995
1989 1996
1990 1997 def api_call_example(method, args):
1991 1998 """
1992 1999 Generates an API call example via CURL
1993 2000 """
1994 2001 args_json = json.dumps(OrderedDict([
1995 2002 ('id', 1),
1996 2003 ('auth_token', 'SECRET'),
1997 2004 ('method', method),
1998 2005 ('args', args)
1999 2006 ]))
2000 2007 return literal(
2001 2008 "curl {api_url} -X POST -H 'content-type:text/plain' --data-binary '{data}'"
2002 2009 "<br/><br/>SECRET can be found in <a href=\"{token_url}\">auth-tokens</a> page, "
2003 2010 "and needs to be of `api calls` role."
2004 2011 .format(
2005 2012 api_url=route_url('apiv2'),
2006 2013 token_url=route_url('my_account_auth_tokens'),
2007 2014 data=args_json))
2008 2015
2009 2016
2010 2017 def notification_description(notification, request):
2011 2018 """
2012 2019 Generate notification human readable description based on notification type
2013 2020 """
2014 2021 from rhodecode.model.notification import NotificationModel
2015 2022 return NotificationModel().make_description(
2016 2023 notification, translate=request.translate)
2017 2024
2018 2025
2019 2026 def go_import_header(request, db_repo=None):
2020 2027 """
2021 2028 Creates a header for go-import functionality in Go Lang
2022 2029 """
2023 2030
2024 2031 if not db_repo:
2025 2032 return
2026 2033 if 'go-get' not in request.GET:
2027 2034 return
2028 2035
2029 2036 clone_url = db_repo.clone_url()
2030 2037 prefix = re.split(r'^https?:\/\/', clone_url)[-1]
2031 2038 # we have a repo and go-get flag,
2032 2039 return literal('<meta name="go-import" content="{} {} {}">'.format(
2033 2040 prefix, db_repo.repo_type, clone_url))
2034 2041
2035 2042
2036 2043 def reviewer_as_json(*args, **kwargs):
2037 2044 from rhodecode.apps.repository.utils import reviewer_as_json as _reviewer_as_json
2038 2045 return _reviewer_as_json(*args, **kwargs)
2039 2046
2040 2047
2041 2048 def get_repo_view_type(request):
2042 2049 route_name = request.matched_route.name
2043 2050 route_to_view_type = {
2044 2051 'repo_changelog': 'changelog',
2045 2052 'repo_files': 'files',
2046 2053 'repo_summary': 'summary',
2047 2054 'repo_commit': 'commit'
2048 2055 }
2049 2056
2050 2057 return route_to_view_type.get(route_name)
@@ -1,2583 +1,2584 b''
1 1 //Primary CSS
2 2
3 3 //--- IMPORTS ------------------//
4 4
5 5 @import 'helpers';
6 6 @import 'mixins';
7 7 @import 'rcicons';
8 8 @import 'variables';
9 9 @import 'bootstrap-variables';
10 10 @import 'form-bootstrap';
11 11 @import 'codemirror';
12 12 @import 'legacy_code_styles';
13 13 @import 'readme-box';
14 14 @import 'progress-bar';
15 15
16 16 @import 'type';
17 17 @import 'alerts';
18 18 @import 'buttons';
19 19 @import 'tags';
20 20 @import 'code-block';
21 21 @import 'examples';
22 22 @import 'login';
23 23 @import 'main-content';
24 24 @import 'select2';
25 25 @import 'comments';
26 26 @import 'panels-bootstrap';
27 27 @import 'panels';
28 28 @import 'deform';
29 29
30 30 //--- BASE ------------------//
31 31 .noscript-error {
32 32 top: 0;
33 33 left: 0;
34 34 width: 100%;
35 35 z-index: 101;
36 36 text-align: center;
37 37 font-size: 120%;
38 38 color: white;
39 39 background-color: @alert2;
40 40 padding: 5px 0 5px 0;
41 41 font-weight: @text-semibold-weight;
42 42 font-family: @text-semibold;
43 43 }
44 44
45 45 html {
46 46 display: table;
47 47 height: 100%;
48 48 width: 100%;
49 49 }
50 50
51 51 body {
52 52 display: table-cell;
53 53 width: 100%;
54 54 }
55 55
56 56 //--- LAYOUT ------------------//
57 57
58 58 .hidden{
59 59 display: none !important;
60 60 }
61 61
62 62 .box{
63 63 float: left;
64 64 width: 100%;
65 65 }
66 66
67 67 .browser-header {
68 68 clear: both;
69 69 }
70 70 .main {
71 71 clear: both;
72 72 padding:0 0 @pagepadding;
73 73 height: auto;
74 74
75 75 &:after { //clearfix
76 76 content:"";
77 77 clear:both;
78 78 width:100%;
79 79 display:block;
80 80 }
81 81 }
82 82
83 83 .action-link{
84 84 margin-left: @padding;
85 85 padding-left: @padding;
86 86 border-left: @border-thickness solid @border-default-color;
87 87 }
88 88
89 89 input + .action-link, .action-link.first{
90 90 border-left: none;
91 91 }
92 92
93 93 .action-link.last{
94 94 margin-right: @padding;
95 95 padding-right: @padding;
96 96 }
97 97
98 98 .action-link.active,
99 99 .action-link.active a{
100 100 color: @grey4;
101 101 }
102 102
103 103 .action-link.disabled {
104 104 color: @grey4;
105 105 cursor: inherit;
106 106 }
107 107
108 108 .clipboard-action {
109 109 cursor: pointer;
110 110 }
111 111
112 112 ul.simple-list{
113 113 list-style: none;
114 114 margin: 0;
115 115 padding: 0;
116 116 }
117 117
118 118 .main-content {
119 119 padding-bottom: @pagepadding;
120 120 }
121 121
122 122 .wide-mode-wrapper {
123 123 max-width:4000px !important;
124 124 }
125 125
126 126 .wrapper {
127 127 position: relative;
128 128 max-width: @wrapper-maxwidth;
129 129 margin: 0 auto;
130 130 }
131 131
132 132 #content {
133 133 clear: both;
134 134 padding: 0 @contentpadding;
135 135 }
136 136
137 137 .advanced-settings-fields{
138 138 input{
139 139 margin-left: @textmargin;
140 140 margin-right: @padding/2;
141 141 }
142 142 }
143 143
144 144 .cs_files_title {
145 145 margin: @pagepadding 0 0;
146 146 }
147 147
148 148 input.inline[type="file"] {
149 149 display: inline;
150 150 }
151 151
152 152 .error_page {
153 153 margin: 10% auto;
154 154
155 155 h1 {
156 156 color: @grey2;
157 157 }
158 158
159 159 .alert {
160 160 margin: @padding 0;
161 161 }
162 162
163 163 .error-branding {
164 164 color: @grey4;
165 165 font-weight: @text-semibold-weight;
166 166 font-family: @text-semibold;
167 167 }
168 168
169 169 .error_message {
170 170 font-family: @text-regular;
171 171 }
172 172
173 173 .sidebar {
174 174 min-height: 275px;
175 175 margin: 0;
176 176 padding: 0 0 @sidebarpadding @sidebarpadding;
177 177 border: none;
178 178 }
179 179
180 180 .main-content {
181 181 position: relative;
182 182 margin: 0 @sidebarpadding @sidebarpadding;
183 183 padding: 0 0 0 @sidebarpadding;
184 184 border-left: @border-thickness solid @grey5;
185 185
186 186 @media (max-width:767px) {
187 187 clear: both;
188 188 width: 100%;
189 189 margin: 0;
190 190 border: none;
191 191 }
192 192 }
193 193
194 194 .inner-column {
195 195 float: left;
196 196 width: 29.75%;
197 197 min-height: 150px;
198 198 margin: @sidebarpadding 2% 0 0;
199 199 padding: 0 2% 0 0;
200 200 border-right: @border-thickness solid @grey5;
201 201
202 202 @media (max-width:767px) {
203 203 clear: both;
204 204 width: 100%;
205 205 border: none;
206 206 }
207 207
208 208 ul {
209 209 padding-left: 1.25em;
210 210 }
211 211
212 212 &:last-child {
213 213 margin: @sidebarpadding 0 0;
214 214 border: none;
215 215 }
216 216
217 217 h4 {
218 218 margin: 0 0 @padding;
219 219 font-weight: @text-semibold-weight;
220 220 font-family: @text-semibold;
221 221 }
222 222 }
223 223 }
224 224 .error-page-logo {
225 225 width: 130px;
226 226 height: 160px;
227 227 }
228 228
229 229 // HEADER
230 230 .header {
231 231
232 232 // TODO: johbo: Fix login pages, so that they work without a min-height
233 233 // for the header and then remove the min-height. I chose a smaller value
234 234 // intentionally here to avoid rendering issues in the main navigation.
235 235 min-height: 49px;
236 236
237 237 position: relative;
238 238 vertical-align: bottom;
239 239 padding: 0 @header-padding;
240 240 background-color: @grey1;
241 241 color: @grey5;
242 242
243 243 .title {
244 244 overflow: visible;
245 245 }
246 246
247 247 &:before,
248 248 &:after {
249 249 content: "";
250 250 clear: both;
251 251 width: 100%;
252 252 }
253 253
254 254 // TODO: johbo: Avoids breaking "Repositories" chooser
255 255 .select2-container .select2-choice .select2-arrow {
256 256 display: none;
257 257 }
258 258 }
259 259
260 260 #header-inner {
261 261 &.title {
262 262 margin: 0;
263 263 }
264 264 &:before,
265 265 &:after {
266 266 content: "";
267 267 clear: both;
268 268 }
269 269 }
270 270
271 271 // Gists
272 272 #files_data {
273 273 clear: both; //for firefox
274 274 }
275 275 #gistid {
276 276 margin-right: @padding;
277 277 }
278 278
279 279 // Global Settings Editor
280 280 .textarea.editor {
281 281 float: left;
282 282 position: relative;
283 283 max-width: @texteditor-width;
284 284
285 285 select {
286 286 position: absolute;
287 287 top:10px;
288 288 right:0;
289 289 }
290 290
291 291 .CodeMirror {
292 292 margin: 0;
293 293 }
294 294
295 295 .help-block {
296 296 margin: 0 0 @padding;
297 297 padding:.5em;
298 298 background-color: @grey6;
299 299 &.pre-formatting {
300 300 white-space: pre;
301 301 }
302 302 }
303 303 }
304 304
305 305 ul.auth_plugins {
306 306 margin: @padding 0 @padding @legend-width;
307 307 padding: 0;
308 308
309 309 li {
310 310 margin-bottom: @padding;
311 311 line-height: 1em;
312 312 list-style-type: none;
313 313
314 314 .auth_buttons .btn {
315 315 margin-right: @padding;
316 316 }
317 317
318 318 }
319 319 }
320 320
321 321
322 322 // My Account PR list
323 323
324 324 #show_closed {
325 325 margin: 0 1em 0 0;
326 326 }
327 327
328 328 .pullrequestlist {
329 329 .closed {
330 330 background-color: @grey6;
331 331 }
332 332 .td-status {
333 333 padding-left: .5em;
334 334 }
335 335 .log-container .truncate {
336 336 height: 2.75em;
337 337 white-space: pre-line;
338 338 }
339 339 table.rctable .user {
340 340 padding-left: 0;
341 341 }
342 342 table.rctable {
343 343 td.td-description,
344 344 .rc-user {
345 345 min-width: auto;
346 346 }
347 347 }
348 348 }
349 349
350 350 // Pull Requests
351 351
352 352 .pullrequests_section_head {
353 353 display: block;
354 354 clear: both;
355 355 margin: @padding 0;
356 356 font-weight: @text-bold-weight;
357 357 font-family: @text-bold;
358 358 }
359 359
360 360 .pr-origininfo, .pr-targetinfo {
361 361 position: relative;
362 362
363 363 .tag {
364 364 display: inline-block;
365 365 margin: 0 1em .5em 0;
366 366 }
367 367
368 368 .clone-url {
369 369 display: inline-block;
370 370 margin: 0 0 .5em 0;
371 371 padding: 0;
372 372 line-height: 1.2em;
373 373 }
374 374 }
375 375
376 376 .pr-mergeinfo {
377 377 min-width: 95% !important;
378 378 padding: 0 !important;
379 379 border: 0;
380 380 }
381 381 .pr-mergeinfo-copy {
382 382 padding: 0 0;
383 383 }
384 384
385 385 .pr-pullinfo {
386 386 min-width: 95% !important;
387 387 padding: 0 !important;
388 388 border: 0;
389 389 }
390 390 .pr-pullinfo-copy {
391 391 padding: 0 0;
392 392 }
393 393
394 394
395 395 #pr-title-input {
396 396 width: 72%;
397 397 font-size: 1em;
398 398 margin: 0;
399 399 padding: 0 0 0 @padding/4;
400 400 line-height: 1.7em;
401 401 color: @text-color;
402 402 letter-spacing: .02em;
403 403 font-weight: @text-bold-weight;
404 404 font-family: @text-bold;
405 405 }
406 406
407 407 #pullrequest_title {
408 408 width: 100%;
409 409 box-sizing: border-box;
410 410 }
411 411
412 412 #pr_open_message {
413 413 border: @border-thickness solid #fff;
414 414 border-radius: @border-radius;
415 415 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
416 416 text-align: left;
417 417 overflow: hidden;
418 418 }
419 419
420 420 .pr-submit-button {
421 421 float: right;
422 422 margin: 0 0 0 5px;
423 423 }
424 424
425 425 .pr-spacing-container {
426 426 padding: 20px;
427 427 clear: both
428 428 }
429 429
430 430 #pr-description-input {
431 431 margin-bottom: 0;
432 432 }
433 433
434 434 .pr-description-label {
435 435 vertical-align: top;
436 436 }
437 437
438 438 .perms_section_head {
439 439 min-width: 625px;
440 440
441 441 h2 {
442 442 margin-bottom: 0;
443 443 }
444 444
445 445 .label-checkbox {
446 446 float: left;
447 447 }
448 448
449 449 &.field {
450 450 margin: @space 0 @padding;
451 451 }
452 452
453 453 &:first-child.field {
454 454 margin-top: 0;
455 455
456 456 .label {
457 457 margin-top: 0;
458 458 padding-top: 0;
459 459 }
460 460
461 461 .radios {
462 462 padding-top: 0;
463 463 }
464 464 }
465 465
466 466 .radios {
467 467 position: relative;
468 468 width: 505px;
469 469 }
470 470 }
471 471
472 472 //--- MODULES ------------------//
473 473
474 474
475 475 // Server Announcement
476 476 #server-announcement {
477 477 width: 95%;
478 478 margin: @padding auto;
479 479 padding: @padding;
480 480 border-width: 2px;
481 481 border-style: solid;
482 482 .border-radius(2px);
483 483 font-weight: @text-bold-weight;
484 484 font-family: @text-bold;
485 485
486 486 &.info { border-color: @alert4; background-color: @alert4-inner; }
487 487 &.warning { border-color: @alert3; background-color: @alert3-inner; }
488 488 &.error { border-color: @alert2; background-color: @alert2-inner; }
489 489 &.success { border-color: @alert1; background-color: @alert1-inner; }
490 490 &.neutral { border-color: @grey3; background-color: @grey6; }
491 491 }
492 492
493 493 // Fixed Sidebar Column
494 494 .sidebar-col-wrapper {
495 495 padding-left: @sidebar-all-width;
496 496
497 497 .sidebar {
498 498 width: @sidebar-width;
499 499 margin-left: -@sidebar-all-width;
500 500 }
501 501 }
502 502
503 503 .sidebar-col-wrapper.scw-small {
504 504 padding-left: @sidebar-small-all-width;
505 505
506 506 .sidebar {
507 507 width: @sidebar-small-width;
508 508 margin-left: -@sidebar-small-all-width;
509 509 }
510 510 }
511 511
512 512
513 513 // FOOTER
514 514 #footer {
515 515 padding: 0;
516 516 text-align: center;
517 517 vertical-align: middle;
518 518 color: @grey2;
519 519 font-size: 11px;
520 520
521 521 p {
522 522 margin: 0;
523 523 padding: 1em;
524 524 line-height: 1em;
525 525 }
526 526
527 527 .server-instance { //server instance
528 528 display: none;
529 529 }
530 530
531 531 .title {
532 532 float: none;
533 533 margin: 0 auto;
534 534 }
535 535 }
536 536
537 537 button.close {
538 538 padding: 0;
539 539 cursor: pointer;
540 540 background: transparent;
541 541 border: 0;
542 542 .box-shadow(none);
543 543 -webkit-appearance: none;
544 544 }
545 545
546 546 .close {
547 547 float: right;
548 548 font-size: 21px;
549 549 font-family: @text-bootstrap;
550 550 line-height: 1em;
551 551 font-weight: bold;
552 552 color: @grey2;
553 553
554 554 &:hover,
555 555 &:focus {
556 556 color: @grey1;
557 557 text-decoration: none;
558 558 cursor: pointer;
559 559 }
560 560 }
561 561
562 562 // GRID
563 563 .sorting,
564 564 .sorting_desc,
565 565 .sorting_asc {
566 566 cursor: pointer;
567 567 }
568 568 .sorting_desc:after {
569 569 content: "\00A0\25B2";
570 570 font-size: .75em;
571 571 }
572 572 .sorting_asc:after {
573 573 content: "\00A0\25BC";
574 574 font-size: .68em;
575 575 }
576 576
577 577
578 578 .user_auth_tokens {
579 579
580 580 &.truncate {
581 581 white-space: nowrap;
582 582 overflow: hidden;
583 583 text-overflow: ellipsis;
584 584 }
585 585
586 586 .fields .field .input {
587 587 margin: 0;
588 588 }
589 589
590 590 input#description {
591 591 width: 100px;
592 592 margin: 0;
593 593 }
594 594
595 595 .drop-menu {
596 596 // TODO: johbo: Remove this, should work out of the box when
597 597 // having multiple inputs inline
598 598 margin: 0 0 0 5px;
599 599 }
600 600 }
601 601 #user_list_table {
602 602 .closed {
603 603 background-color: @grey6;
604 604 }
605 605 }
606 606
607 607
608 608 input, textarea {
609 609 &.disabled {
610 610 opacity: .5;
611 611 }
612 612
613 613 &:hover {
614 614 border-color: @grey3;
615 615 box-shadow: @button-shadow;
616 616 }
617 617
618 618 &:focus {
619 619 border-color: @rcblue;
620 620 box-shadow: @button-shadow;
621 621 }
622 622 }
623 623
624 624 // remove extra padding in firefox
625 625 input::-moz-focus-inner { border:0; padding:0 }
626 626
627 627 .adjacent input {
628 628 margin-bottom: @padding;
629 629 }
630 630
631 631 .permissions_boxes {
632 632 display: block;
633 633 }
634 634
635 635 //FORMS
636 636
637 637 .medium-inline,
638 638 input#description.medium-inline {
639 639 display: inline;
640 640 width: @medium-inline-input-width;
641 641 min-width: 100px;
642 642 }
643 643
644 644 select {
645 645 //reset
646 646 -webkit-appearance: none;
647 647 -moz-appearance: none;
648 648
649 649 display: inline-block;
650 650 height: 28px;
651 651 width: auto;
652 652 margin: 0 @padding @padding 0;
653 653 padding: 0 18px 0 8px;
654 654 line-height:1em;
655 655 font-size: @basefontsize;
656 656 border: @border-thickness solid @grey5;
657 657 border-radius: @border-radius;
658 658 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
659 659 color: @grey4;
660 660 box-shadow: @button-shadow;
661 661
662 662 &:after {
663 663 content: "\00A0\25BE";
664 664 }
665 665
666 666 &:focus, &:hover {
667 667 outline: none;
668 668 border-color: @grey4;
669 669 color: @rcdarkblue;
670 670 }
671 671 }
672 672
673 673 option {
674 674 &:focus {
675 675 outline: none;
676 676 }
677 677 }
678 678
679 679 input,
680 680 textarea {
681 681 padding: @input-padding;
682 682 border: @input-border-thickness solid @border-highlight-color;
683 683 .border-radius (@border-radius);
684 684 font-family: @text-light;
685 685 font-size: @basefontsize;
686 686
687 687 &.input-sm {
688 688 padding: 5px;
689 689 }
690 690
691 691 &#description {
692 692 min-width: @input-description-minwidth;
693 693 min-height: 1em;
694 694 padding: 10px;
695 695 }
696 696 }
697 697
698 698 .field-sm {
699 699 input,
700 700 textarea {
701 701 padding: 5px;
702 702 }
703 703 }
704 704
705 705 textarea {
706 706 display: block;
707 707 clear: both;
708 708 width: 100%;
709 709 min-height: 100px;
710 710 margin-bottom: @padding;
711 711 .box-sizing(border-box);
712 712 overflow: auto;
713 713 }
714 714
715 715 label {
716 716 font-family: @text-light;
717 717 }
718 718
719 719 // GRAVATARS
720 720 // centers gravatar on username to the right
721 721
722 722 .gravatar {
723 723 display: inline;
724 724 min-width: 16px;
725 725 min-height: 16px;
726 726 margin: -5px 0;
727 727 padding: 0;
728 728 line-height: 1em;
729 729 box-sizing: content-box;
730 730 border-radius: 50%;
731 731
732 732 &.gravatar-large {
733 733 margin: -0.5em .25em -0.5em 0;
734 734 }
735 735
736 736 & + .user {
737 737 display: inline;
738 738 margin: 0;
739 739 padding: 0 0 0 .17em;
740 740 line-height: 1em;
741 741 }
742 742 }
743 743
744 744 .user-inline-data {
745 745 display: inline-block;
746 746 float: left;
747 747 padding-left: .5em;
748 748 line-height: 1.3em;
749 749 }
750 750
751 751 .rc-user { // gravatar + user wrapper
752 752 float: left;
753 753 position: relative;
754 754 min-width: 100px;
755 755 max-width: 200px;
756 756 min-height: (@gravatar-size + @border-thickness * 2); // account for border
757 757 display: block;
758 758 padding: 0 0 0 (@gravatar-size + @basefontsize/2 + @border-thickness * 2);
759 759
760 760
761 761 .gravatar {
762 762 display: block;
763 763 position: absolute;
764 764 top: 0;
765 765 left: 0;
766 766 min-width: @gravatar-size;
767 767 min-height: @gravatar-size;
768 768 margin: 0;
769 769 }
770 770
771 771 .user {
772 772 display: block;
773 773 max-width: 175px;
774 774 padding-top: 2px;
775 775 overflow: hidden;
776 776 text-overflow: ellipsis;
777 777 }
778 778 }
779 779
780 780 .gist-gravatar,
781 781 .journal_container {
782 782 .gravatar-large {
783 783 margin: 0 .5em -10px 0;
784 784 }
785 785 }
786 786
787 787
788 788 // ADMIN SETTINGS
789 789
790 790 // Tag Patterns
791 791 .tag_patterns {
792 792 .tag_input {
793 793 margin-bottom: @padding;
794 794 }
795 795 }
796 796
797 797 .locked_input {
798 798 position: relative;
799 799
800 800 input {
801 801 display: inline;
802 802 margin: 3px 5px 0px 0px;
803 803 }
804 804
805 805 br {
806 806 display: none;
807 807 }
808 808
809 809 .error-message {
810 810 float: left;
811 811 width: 100%;
812 812 }
813 813
814 814 .lock_input_button {
815 815 display: inline;
816 816 }
817 817
818 818 .help-block {
819 819 clear: both;
820 820 }
821 821 }
822 822
823 823 // Notifications
824 824
825 825 .notifications_buttons {
826 826 margin: 0 0 @space 0;
827 827 padding: 0;
828 828
829 829 .btn {
830 830 display: inline-block;
831 831 }
832 832 }
833 833
834 834 .notification-list {
835 835
836 836 div {
837 837 display: inline-block;
838 838 vertical-align: middle;
839 839 }
840 840
841 841 .container {
842 842 display: block;
843 843 margin: 0 0 @padding 0;
844 844 }
845 845
846 846 .delete-notifications {
847 847 margin-left: @padding;
848 848 text-align: right;
849 849 cursor: pointer;
850 850 }
851 851
852 852 .read-notifications {
853 853 margin-left: @padding/2;
854 854 text-align: right;
855 855 width: 35px;
856 856 cursor: pointer;
857 857 }
858 858
859 859 .icon-minus-sign {
860 860 color: @alert2;
861 861 }
862 862
863 863 .icon-ok-sign {
864 864 color: @alert1;
865 865 }
866 866 }
867 867
868 868 .user_settings {
869 869 float: left;
870 870 clear: both;
871 871 display: block;
872 872 width: 100%;
873 873
874 874 .gravatar_box {
875 875 margin-bottom: @padding;
876 876
877 877 &:after {
878 878 content: " ";
879 879 clear: both;
880 880 width: 100%;
881 881 }
882 882 }
883 883
884 884 .fields .field {
885 885 clear: both;
886 886 }
887 887 }
888 888
889 889 .advanced_settings {
890 890 margin-bottom: @space;
891 891
892 892 .help-block {
893 893 margin-left: 0;
894 894 }
895 895
896 896 button + .help-block {
897 897 margin-top: @padding;
898 898 }
899 899 }
900 900
901 901 // admin settings radio buttons and labels
902 902 .label-2 {
903 903 float: left;
904 904 width: @label2-width;
905 905
906 906 label {
907 907 color: @grey1;
908 908 }
909 909 }
910 910 .checkboxes {
911 911 float: left;
912 912 width: @checkboxes-width;
913 913 margin-bottom: @padding;
914 914
915 915 .checkbox {
916 916 width: 100%;
917 917
918 918 label {
919 919 margin: 0;
920 920 padding: 0;
921 921 }
922 922 }
923 923
924 924 .checkbox + .checkbox {
925 925 display: inline-block;
926 926 }
927 927
928 928 label {
929 929 margin-right: 1em;
930 930 }
931 931 }
932 932
933 933 // CHANGELOG
934 934 .container_header {
935 935 float: left;
936 936 display: block;
937 937 width: 100%;
938 938 margin: @padding 0 @padding;
939 939
940 940 #filter_changelog {
941 941 float: left;
942 942 margin-right: @padding;
943 943 }
944 944
945 945 .breadcrumbs_light {
946 946 display: inline-block;
947 947 }
948 948 }
949 949
950 950 .info_box {
951 951 float: right;
952 952 }
953 953
954 954
955 955 #graph_nodes {
956 956 padding-top: 43px;
957 957 }
958 958
959 959 #graph_content{
960 960
961 961 // adjust for table headers so that graph renders properly
962 962 // #graph_nodes padding - table cell padding
963 963 padding-top: (@space - (@basefontsize * 2.4));
964 964
965 965 &.graph_full_width {
966 966 width: 100%;
967 967 max-width: 100%;
968 968 }
969 969 }
970 970
971 971 #graph {
972 972 .flag_status {
973 973 margin: 0;
974 974 }
975 975
976 976 .pagination-left {
977 977 float: left;
978 978 clear: both;
979 979 }
980 980
981 981 .log-container {
982 982 max-width: 345px;
983 983
984 984 .message{
985 985 max-width: 340px;
986 986 }
987 987 }
988 988
989 989 .graph-col-wrapper {
990 990 padding-left: 110px;
991 991
992 992 #graph_nodes {
993 993 width: 100px;
994 994 margin-left: -110px;
995 995 float: left;
996 996 clear: left;
997 997 }
998 998 }
999 999
1000 1000 .load-more-commits {
1001 1001 text-align: center;
1002 1002 }
1003 1003 .load-more-commits:hover {
1004 1004 background-color: @grey7;
1005 1005 }
1006 1006 .load-more-commits {
1007 1007 a {
1008 1008 display: block;
1009 1009 }
1010 1010 }
1011 1011 }
1012 1012
1013 1013 #filter_changelog {
1014 1014 float: left;
1015 1015 }
1016 1016
1017 1017
1018 1018 //--- THEME ------------------//
1019 1019
1020 1020 #logo {
1021 1021 float: left;
1022 1022 margin: 9px 0 0 0;
1023 1023
1024 1024 .header {
1025 1025 background-color: transparent;
1026 1026 }
1027 1027
1028 1028 a {
1029 1029 display: inline-block;
1030 1030 }
1031 1031
1032 1032 img {
1033 1033 height:30px;
1034 1034 }
1035 1035 }
1036 1036
1037 1037 .logo-wrapper {
1038 1038 float:left;
1039 1039 }
1040 1040
1041 1041 .branding {
1042 1042 float: left;
1043 1043 padding: 9px 2px;
1044 1044 line-height: 1em;
1045 1045 font-size: @navigation-fontsize;
1046 1046
1047 1047 a {
1048 1048 color: @grey5
1049 1049 }
1050 1050 }
1051 1051
1052 1052 img {
1053 1053 border: none;
1054 1054 outline: none;
1055 1055 }
1056 1056 user-profile-header
1057 1057 label {
1058 1058
1059 1059 input[type="checkbox"] {
1060 1060 margin-right: 1em;
1061 1061 }
1062 1062 input[type="radio"] {
1063 1063 margin-right: 1em;
1064 1064 }
1065 1065 }
1066 1066
1067 1067 .flag_status {
1068 1068 margin: 2px;
1069 1069 &.under_review {
1070 1070 .circle(5px, @alert3);
1071 1071 }
1072 1072 &.approved {
1073 1073 .circle(5px, @alert1);
1074 1074 }
1075 1075 &.rejected,
1076 1076 &.forced_closed{
1077 1077 .circle(5px, @alert2);
1078 1078 }
1079 1079 &.not_reviewed {
1080 1080 .circle(5px, @grey5);
1081 1081 }
1082 1082 }
1083 1083
1084 1084 .flag_status_comment_box {
1085 1085 margin: 5px 6px 0px 2px;
1086 1086 }
1087 1087 .test_pattern_preview {
1088 1088 margin: @space 0;
1089 1089
1090 1090 p {
1091 1091 margin-bottom: 0;
1092 1092 border-bottom: @border-thickness solid @border-default-color;
1093 1093 color: @grey3;
1094 1094 }
1095 1095
1096 1096 .btn {
1097 1097 margin-bottom: @padding;
1098 1098 }
1099 1099 }
1100 1100 #test_pattern_result {
1101 1101 display: none;
1102 1102 &:extend(pre);
1103 1103 padding: .9em;
1104 1104 color: @grey3;
1105 1105 background-color: @grey7;
1106 1106 border-right: @border-thickness solid @border-default-color;
1107 1107 border-bottom: @border-thickness solid @border-default-color;
1108 1108 border-left: @border-thickness solid @border-default-color;
1109 1109 }
1110 1110
1111 1111 #repo_vcs_settings {
1112 1112 #inherit_overlay_vcs_default {
1113 1113 display: none;
1114 1114 }
1115 1115 #inherit_overlay_vcs_custom {
1116 1116 display: custom;
1117 1117 }
1118 1118 &.inherited {
1119 1119 #inherit_overlay_vcs_default {
1120 1120 display: block;
1121 1121 }
1122 1122 #inherit_overlay_vcs_custom {
1123 1123 display: none;
1124 1124 }
1125 1125 }
1126 1126 }
1127 1127
1128 1128 .issue-tracker-link {
1129 1129 color: @rcblue;
1130 1130 }
1131 1131
1132 1132 // Issue Tracker Table Show/Hide
1133 1133 #repo_issue_tracker {
1134 1134 #inherit_overlay {
1135 1135 display: none;
1136 1136 }
1137 1137 #custom_overlay {
1138 1138 display: custom;
1139 1139 }
1140 1140 &.inherited {
1141 1141 #inherit_overlay {
1142 1142 display: block;
1143 1143 }
1144 1144 #custom_overlay {
1145 1145 display: none;
1146 1146 }
1147 1147 }
1148 1148 }
1149 1149 table.issuetracker {
1150 1150 &.readonly {
1151 1151 tr, td {
1152 1152 color: @grey3;
1153 1153 }
1154 1154 }
1155 1155 .edit {
1156 1156 display: none;
1157 1157 }
1158 1158 .editopen {
1159 1159 .edit {
1160 1160 display: inline;
1161 1161 }
1162 1162 .entry {
1163 1163 display: none;
1164 1164 }
1165 1165 }
1166 1166 tr td.td-action {
1167 1167 min-width: 117px;
1168 1168 }
1169 1169 td input {
1170 1170 max-width: none;
1171 1171 min-width: 30px;
1172 1172 width: 80%;
1173 1173 }
1174 1174 .issuetracker_pref input {
1175 1175 width: 40%;
1176 1176 }
1177 1177 input.edit_issuetracker_update {
1178 1178 margin-right: 0;
1179 1179 width: auto;
1180 1180 }
1181 1181 }
1182 1182
1183 1183 table.integrations {
1184 1184 .td-icon {
1185 1185 width: 20px;
1186 1186 .integration-icon {
1187 1187 height: 20px;
1188 1188 width: 20px;
1189 1189 }
1190 1190 }
1191 1191 }
1192 1192
1193 1193 .integrations {
1194 1194 a.integration-box {
1195 1195 color: @text-color;
1196 1196 &:hover {
1197 1197 .panel {
1198 1198 background: #fbfbfb;
1199 1199 }
1200 1200 }
1201 1201 .integration-icon {
1202 1202 width: 30px;
1203 1203 height: 30px;
1204 1204 margin-right: 20px;
1205 1205 float: left;
1206 1206 }
1207 1207
1208 1208 .panel-body {
1209 1209 padding: 10px;
1210 1210 }
1211 1211 .panel {
1212 1212 margin-bottom: 10px;
1213 1213 }
1214 1214 h2 {
1215 1215 display: inline-block;
1216 1216 margin: 0;
1217 1217 min-width: 140px;
1218 1218 }
1219 1219 }
1220 1220 a.integration-box.dummy-integration {
1221 1221 color: @grey4
1222 1222 }
1223 1223 }
1224 1224
1225 1225 //Permissions Settings
1226 1226 #add_perm {
1227 1227 margin: 0 0 @padding;
1228 1228 cursor: pointer;
1229 1229 }
1230 1230
1231 1231 .perm_ac {
1232 1232 input {
1233 1233 width: 95%;
1234 1234 }
1235 1235 }
1236 1236
1237 1237 .autocomplete-suggestions {
1238 1238 width: auto !important; // overrides autocomplete.js
1239 1239 min-width: 278px;
1240 1240 margin: 0;
1241 1241 border: @border-thickness solid @grey5;
1242 1242 border-radius: @border-radius;
1243 1243 color: @grey2;
1244 1244 background-color: white;
1245 1245 }
1246 1246
1247 1247 .autocomplete-selected {
1248 1248 background: #F0F0F0;
1249 1249 }
1250 1250
1251 1251 .ac-container-wrap {
1252 1252 margin: 0;
1253 1253 padding: 8px;
1254 1254 border-bottom: @border-thickness solid @grey5;
1255 1255 list-style-type: none;
1256 1256 cursor: pointer;
1257 1257
1258 1258 &:hover {
1259 1259 background-color: @grey7;
1260 1260 }
1261 1261
1262 1262 img {
1263 1263 height: @gravatar-size;
1264 1264 width: @gravatar-size;
1265 1265 margin-right: 1em;
1266 1266 }
1267 1267
1268 1268 strong {
1269 1269 font-weight: normal;
1270 1270 }
1271 1271 }
1272 1272
1273 1273 // Settings Dropdown
1274 1274 .user-menu .container {
1275 1275 padding: 0 4px;
1276 1276 margin: 0;
1277 1277 }
1278 1278
1279 1279 .user-menu .gravatar {
1280 1280 cursor: pointer;
1281 1281 }
1282 1282
1283 1283 .codeblock {
1284 1284 margin-bottom: @padding;
1285 1285 clear: both;
1286 1286
1287 1287 .stats {
1288 1288 overflow: hidden;
1289 1289 }
1290 1290
1291 1291 .message{
1292 1292 textarea{
1293 1293 margin: 0;
1294 1294 }
1295 1295 }
1296 1296
1297 1297 .code-header {
1298 1298 .stats {
1299 1299 line-height: 2em;
1300 1300
1301 1301 .revision_id {
1302 1302 margin-left: 0;
1303 1303 }
1304 1304 .buttons {
1305 1305 padding-right: 0;
1306 1306 }
1307 1307 }
1308 1308
1309 1309 .item{
1310 1310 margin-right: 0.5em;
1311 1311 }
1312 1312 }
1313 1313
1314 1314 #editor_container{
1315 1315 position: relative;
1316 1316 margin: @padding;
1317 1317 }
1318 1318 }
1319 1319
1320 1320 #file_history_container {
1321 1321 display: none;
1322 1322 }
1323 1323
1324 1324 .file-history-inner {
1325 1325 margin-bottom: 10px;
1326 1326 }
1327 1327
1328 1328 // Pull Requests
1329 1329 .summary-details {
1330 1330 width: 72%;
1331 1331 }
1332 1332 .pr-summary {
1333 1333 border-bottom: @border-thickness solid @grey5;
1334 1334 margin-bottom: @space;
1335 1335 }
1336 1336 .reviewers-title {
1337 1337 width: 25%;
1338 1338 min-width: 200px;
1339 1339 }
1340 1340 .reviewers {
1341 1341 width: 25%;
1342 1342 min-width: 200px;
1343 1343 }
1344 1344 .reviewers ul li {
1345 1345 position: relative;
1346 1346 width: 100%;
1347 1347 padding-bottom: 8px;
1348 1348 list-style-type: none;
1349 1349 }
1350 1350
1351 1351 .reviewer_entry {
1352 1352 min-height: 55px;
1353 1353 }
1354 1354
1355 1355 .reviewers_member {
1356 1356 width: 100%;
1357 1357 overflow: auto;
1358 1358 }
1359 1359 .reviewer_reason {
1360 1360 padding-left: 20px;
1361 1361 line-height: 1.5em;
1362 1362 }
1363 1363 .reviewer_status {
1364 1364 display: inline-block;
1365 1365 vertical-align: top;
1366 1366 width: 25px;
1367 1367 min-width: 25px;
1368 1368 height: 1.2em;
1369 1369 margin-top: 3px;
1370 1370 line-height: 1em;
1371 1371 }
1372 1372
1373 1373 .reviewer_name {
1374 1374 display: inline-block;
1375 1375 max-width: 83%;
1376 1376 padding-right: 20px;
1377 1377 vertical-align: middle;
1378 1378 line-height: 1;
1379 1379
1380 1380 .rc-user {
1381 1381 min-width: 0;
1382 1382 margin: -2px 1em 0 0;
1383 1383 }
1384 1384
1385 1385 .reviewer {
1386 1386 float: left;
1387 1387 }
1388 1388 }
1389 1389
1390 1390 .reviewer_member_mandatory {
1391 1391 position: absolute;
1392 1392 left: 15px;
1393 1393 top: 8px;
1394 1394 width: 16px;
1395 1395 font-size: 11px;
1396 1396 margin: 0;
1397 1397 padding: 0;
1398 1398 color: black;
1399 1399 }
1400 1400
1401 1401 .reviewer_member_mandatory_remove,
1402 1402 .reviewer_member_remove {
1403 1403 position: absolute;
1404 1404 right: 0;
1405 1405 top: 0;
1406 1406 width: 16px;
1407 1407 margin-bottom: 10px;
1408 1408 padding: 0;
1409 1409 color: black;
1410 1410 }
1411 1411
1412 1412 .reviewer_member_mandatory_remove {
1413 1413 color: @grey4;
1414 1414 }
1415 1415
1416 1416 .reviewer_member_status {
1417 1417 margin-top: 5px;
1418 1418 }
1419 1419 .pr-summary #summary{
1420 1420 width: 100%;
1421 1421 }
1422 1422 .pr-summary .action_button:hover {
1423 1423 border: 0;
1424 1424 cursor: pointer;
1425 1425 }
1426 1426 .pr-details-title {
1427 1427 padding-bottom: 8px;
1428 1428 border-bottom: @border-thickness solid @grey5;
1429 1429
1430 1430 .action_button.disabled {
1431 1431 color: @grey4;
1432 1432 cursor: inherit;
1433 1433 }
1434 1434 .action_button {
1435 1435 color: @rcblue;
1436 1436 }
1437 1437 }
1438 1438 .pr-details-content {
1439 1439 margin-top: @textmargin;
1440 1440 margin-bottom: @textmargin;
1441 1441 }
1442 1442
1443 1443 .pr-reviewer-rules {
1444 1444 padding: 10px 0px 20px 0px;
1445 1445 }
1446 1446
1447 1447 .group_members {
1448 1448 margin-top: 0;
1449 1449 padding: 0;
1450 1450 list-style: outside none none;
1451 1451
1452 1452 img {
1453 1453 height: @gravatar-size;
1454 1454 width: @gravatar-size;
1455 1455 margin-right: .5em;
1456 1456 margin-left: 3px;
1457 1457 }
1458 1458
1459 1459 .to-delete {
1460 1460 .user {
1461 1461 text-decoration: line-through;
1462 1462 }
1463 1463 }
1464 1464 }
1465 1465
1466 1466 .compare_view_commits_title {
1467 1467 .disabled {
1468 1468 cursor: inherit;
1469 1469 &:hover{
1470 1470 background-color: inherit;
1471 1471 color: inherit;
1472 1472 }
1473 1473 }
1474 1474 }
1475 1475
1476 1476 .subtitle-compare {
1477 1477 margin: -15px 0px 0px 0px;
1478 1478 }
1479 1479
1480 1480 .comments-summary-td {
1481 1481 border-top: 1px dashed @grey5;
1482 1482 }
1483 1483
1484 1484 // new entry in group_members
1485 1485 .td-author-new-entry {
1486 1486 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1487 1487 }
1488 1488
1489 1489 .usergroup_member_remove {
1490 1490 width: 16px;
1491 1491 margin-bottom: 10px;
1492 1492 padding: 0;
1493 1493 color: black !important;
1494 1494 cursor: pointer;
1495 1495 }
1496 1496
1497 1497 .reviewer_ac .ac-input {
1498 1498 width: 92%;
1499 1499 margin-bottom: 1em;
1500 1500 }
1501 1501
1502 1502 .compare_view_commits tr{
1503 1503 height: 20px;
1504 1504 }
1505 1505 .compare_view_commits td {
1506 1506 vertical-align: top;
1507 1507 padding-top: 10px;
1508 1508 }
1509 1509 .compare_view_commits .author {
1510 1510 margin-left: 5px;
1511 1511 }
1512 1512
1513 1513 .compare_view_commits {
1514 1514 .color-a {
1515 1515 color: @alert1;
1516 1516 }
1517 1517
1518 1518 .color-c {
1519 1519 color: @color3;
1520 1520 }
1521 1521
1522 1522 .color-r {
1523 1523 color: @color5;
1524 1524 }
1525 1525
1526 1526 .color-a-bg {
1527 1527 background-color: @alert1;
1528 1528 }
1529 1529
1530 1530 .color-c-bg {
1531 1531 background-color: @alert3;
1532 1532 }
1533 1533
1534 1534 .color-r-bg {
1535 1535 background-color: @alert2;
1536 1536 }
1537 1537
1538 1538 .color-a-border {
1539 1539 border: 1px solid @alert1;
1540 1540 }
1541 1541
1542 1542 .color-c-border {
1543 1543 border: 1px solid @alert3;
1544 1544 }
1545 1545
1546 1546 .color-r-border {
1547 1547 border: 1px solid @alert2;
1548 1548 }
1549 1549
1550 1550 .commit-change-indicator {
1551 1551 width: 15px;
1552 1552 height: 15px;
1553 1553 position: relative;
1554 1554 left: 15px;
1555 1555 }
1556 1556
1557 1557 .commit-change-content {
1558 1558 text-align: center;
1559 1559 vertical-align: middle;
1560 1560 line-height: 15px;
1561 1561 }
1562 1562 }
1563 1563
1564 1564 .compare_view_filepath {
1565 1565 color: @grey1;
1566 1566 }
1567 1567
1568 1568 .show_more {
1569 1569 display: inline-block;
1570 1570 width: 0;
1571 1571 height: 0;
1572 1572 vertical-align: middle;
1573 1573 content: "";
1574 1574 border: 4px solid;
1575 1575 border-right-color: transparent;
1576 1576 border-bottom-color: transparent;
1577 1577 border-left-color: transparent;
1578 1578 font-size: 0;
1579 1579 }
1580 1580
1581 1581 .journal_more .show_more {
1582 1582 display: inline;
1583 1583
1584 1584 &:after {
1585 1585 content: none;
1586 1586 }
1587 1587 }
1588 1588
1589 1589 .compare_view_commits .collapse_commit:after {
1590 1590 cursor: pointer;
1591 1591 content: "\00A0\25B4";
1592 1592 margin-left: -3px;
1593 1593 font-size: 17px;
1594 1594 color: @grey4;
1595 1595 }
1596 1596
1597 1597 .diff_links {
1598 1598 margin-left: 8px;
1599 1599 }
1600 1600
1601 1601 div.ancestor {
1602 1602 margin: -30px 0px;
1603 1603 }
1604 1604
1605 1605 .cs_icon_td input[type="checkbox"] {
1606 1606 display: none;
1607 1607 }
1608 1608
1609 1609 .cs_icon_td .expand_file_icon:after {
1610 1610 cursor: pointer;
1611 1611 content: "\00A0\25B6";
1612 1612 font-size: 12px;
1613 1613 color: @grey4;
1614 1614 }
1615 1615
1616 1616 .cs_icon_td .collapse_file_icon:after {
1617 1617 cursor: pointer;
1618 1618 content: "\00A0\25BC";
1619 1619 font-size: 12px;
1620 1620 color: @grey4;
1621 1621 }
1622 1622
1623 1623 /*new binary
1624 1624 NEW_FILENODE = 1
1625 1625 DEL_FILENODE = 2
1626 1626 MOD_FILENODE = 3
1627 1627 RENAMED_FILENODE = 4
1628 1628 COPIED_FILENODE = 5
1629 1629 CHMOD_FILENODE = 6
1630 1630 BIN_FILENODE = 7
1631 1631 */
1632 1632 .cs_files_expand {
1633 1633 font-size: @basefontsize + 5px;
1634 1634 line-height: 1.8em;
1635 1635 float: right;
1636 1636 }
1637 1637
1638 1638 .cs_files_expand span{
1639 1639 color: @rcblue;
1640 1640 cursor: pointer;
1641 1641 }
1642 1642 .cs_files {
1643 1643 clear: both;
1644 1644 padding-bottom: @padding;
1645 1645
1646 1646 .cur_cs {
1647 1647 margin: 10px 2px;
1648 1648 font-weight: bold;
1649 1649 }
1650 1650
1651 1651 .node {
1652 1652 float: left;
1653 1653 }
1654 1654
1655 1655 .changes {
1656 1656 float: right;
1657 1657 color: white;
1658 1658 font-size: @basefontsize - 4px;
1659 1659 margin-top: 4px;
1660 1660 opacity: 0.6;
1661 1661 filter: Alpha(opacity=60); /* IE8 and earlier */
1662 1662
1663 1663 .added {
1664 1664 background-color: @alert1;
1665 1665 float: left;
1666 1666 text-align: center;
1667 1667 }
1668 1668
1669 1669 .deleted {
1670 1670 background-color: @alert2;
1671 1671 float: left;
1672 1672 text-align: center;
1673 1673 }
1674 1674
1675 1675 .bin {
1676 1676 background-color: @alert1;
1677 1677 text-align: center;
1678 1678 }
1679 1679
1680 1680 /*new binary*/
1681 1681 .bin.bin1 {
1682 1682 background-color: @alert1;
1683 1683 text-align: center;
1684 1684 }
1685 1685
1686 1686 /*deleted binary*/
1687 1687 .bin.bin2 {
1688 1688 background-color: @alert2;
1689 1689 text-align: center;
1690 1690 }
1691 1691
1692 1692 /*mod binary*/
1693 1693 .bin.bin3 {
1694 1694 background-color: @grey2;
1695 1695 text-align: center;
1696 1696 }
1697 1697
1698 1698 /*rename file*/
1699 1699 .bin.bin4 {
1700 1700 background-color: @alert4;
1701 1701 text-align: center;
1702 1702 }
1703 1703
1704 1704 /*copied file*/
1705 1705 .bin.bin5 {
1706 1706 background-color: @alert4;
1707 1707 text-align: center;
1708 1708 }
1709 1709
1710 1710 /*chmod file*/
1711 1711 .bin.bin6 {
1712 1712 background-color: @grey2;
1713 1713 text-align: center;
1714 1714 }
1715 1715 }
1716 1716 }
1717 1717
1718 1718 .cs_files .cs_added, .cs_files .cs_A,
1719 1719 .cs_files .cs_added, .cs_files .cs_M,
1720 1720 .cs_files .cs_added, .cs_files .cs_D {
1721 1721 height: 16px;
1722 1722 padding-right: 10px;
1723 1723 margin-top: 7px;
1724 1724 text-align: left;
1725 1725 }
1726 1726
1727 1727 .cs_icon_td {
1728 1728 min-width: 16px;
1729 1729 width: 16px;
1730 1730 }
1731 1731
1732 1732 .pull-request-merge {
1733 1733 border: 1px solid @grey5;
1734 1734 padding: 10px 0px 20px;
1735 1735 margin-top: 10px;
1736 1736 margin-bottom: 20px;
1737 1737 }
1738 1738
1739 1739 .pull-request-merge ul {
1740 1740 padding: 0px 0px;
1741 1741 }
1742 1742
1743 1743 .pull-request-merge li {
1744 1744 list-style-type: none;
1745 1745 }
1746 1746
1747 1747 .pull-request-merge .pull-request-wrap {
1748 1748 height: auto;
1749 1749 padding: 0px 0px;
1750 1750 text-align: right;
1751 1751 }
1752 1752
1753 1753 .pull-request-merge span {
1754 1754 margin-right: 5px;
1755 1755 }
1756 1756
1757 1757 .pull-request-merge-actions {
1758 1758 min-height: 30px;
1759 1759 padding: 0px 0px;
1760 1760 }
1761 1761
1762 1762 .pull-request-merge-info {
1763 1763 padding: 0px 5px 5px 0px;
1764 1764 }
1765 1765
1766 1766 .merge-status {
1767 1767 margin-right: 5px;
1768 1768 }
1769 1769
1770 1770 .merge-message {
1771 1771 font-size: 1.2em
1772 1772 }
1773 1773
1774 1774 .merge-message.success i,
1775 1775 .merge-icon.success i {
1776 1776 color:@alert1;
1777 1777 }
1778 1778
1779 1779 .merge-message.warning i,
1780 1780 .merge-icon.warning i {
1781 1781 color: @alert3;
1782 1782 }
1783 1783
1784 1784 .merge-message.error i,
1785 1785 .merge-icon.error i {
1786 1786 color:@alert2;
1787 1787 }
1788 1788
1789 1789 .pr-versions {
1790 1790 font-size: 1.1em;
1791 1791
1792 1792 table {
1793 1793 padding: 0px 5px;
1794 1794 }
1795 1795
1796 1796 td {
1797 1797 line-height: 15px;
1798 1798 }
1799 1799
1800 1800 .flag_status {
1801 1801 margin: 0;
1802 1802 }
1803 1803
1804 1804 .compare-radio-button {
1805 1805 position: relative;
1806 1806 top: -3px;
1807 1807 }
1808 1808 }
1809 1809
1810 1810
1811 1811 #close_pull_request {
1812 1812 margin-right: 0px;
1813 1813 }
1814 1814
1815 1815 .empty_data {
1816 1816 color: @grey4;
1817 1817 }
1818 1818
1819 1819 #changeset_compare_view_content {
1820 1820 clear: both;
1821 1821 width: 100%;
1822 1822 box-sizing: border-box;
1823 1823 .border-radius(@border-radius);
1824 1824
1825 1825 .help-block {
1826 1826 margin: @padding 0;
1827 1827 color: @text-color;
1828 1828 &.pre-formatting {
1829 1829 white-space: pre;
1830 1830 }
1831 1831 }
1832 1832
1833 1833 .empty_data {
1834 1834 margin: @padding 0;
1835 1835 }
1836 1836
1837 1837 .alert {
1838 1838 margin-bottom: @space;
1839 1839 }
1840 1840 }
1841 1841
1842 1842 .table_disp {
1843 1843 .status {
1844 1844 width: auto;
1845 1845
1846 1846 .flag_status {
1847 1847 float: left;
1848 1848 }
1849 1849 }
1850 1850 }
1851 1851
1852 1852
1853 1853 .creation_in_progress {
1854 1854 color: @grey4
1855 1855 }
1856 1856
1857 1857 .status_box_menu {
1858 1858 margin: 0;
1859 1859 }
1860 1860
1861 1861 .notification-table{
1862 1862 margin-bottom: @space;
1863 1863 display: table;
1864 1864 width: 100%;
1865 1865
1866 1866 .container{
1867 1867 display: table-row;
1868 1868
1869 1869 .notification-header{
1870 1870 border-bottom: @border-thickness solid @border-default-color;
1871 1871 }
1872 1872
1873 1873 .notification-subject{
1874 1874 display: table-cell;
1875 1875 }
1876 1876 }
1877 1877 }
1878 1878
1879 1879 // Notifications
1880 1880 .notification-header{
1881 1881 display: table;
1882 1882 width: 100%;
1883 1883 padding: floor(@basefontsize/2) 0;
1884 1884 line-height: 1em;
1885 1885
1886 1886 .desc, .delete-notifications, .read-notifications{
1887 1887 display: table-cell;
1888 1888 text-align: left;
1889 1889 }
1890 1890
1891 1891 .desc{
1892 1892 width: 1163px;
1893 1893 }
1894 1894
1895 1895 .delete-notifications, .read-notifications{
1896 1896 width: 35px;
1897 1897 min-width: 35px; //fixes when only one button is displayed
1898 1898 }
1899 1899 }
1900 1900
1901 1901 .notification-body {
1902 1902 .markdown-block,
1903 1903 .rst-block {
1904 1904 padding: @padding 0;
1905 1905 }
1906 1906
1907 1907 .notification-subject {
1908 1908 padding: @textmargin 0;
1909 1909 border-bottom: @border-thickness solid @border-default-color;
1910 1910 }
1911 1911 }
1912 1912
1913 1913
1914 1914 .notifications_buttons{
1915 1915 float: right;
1916 1916 }
1917 1917
1918 1918 #notification-status{
1919 1919 display: inline;
1920 1920 }
1921 1921
1922 1922 // Repositories
1923 1923
1924 1924 #summary.fields{
1925 1925 display: table;
1926 1926
1927 1927 .field{
1928 1928 display: table-row;
1929 1929
1930 1930 .label-summary{
1931 1931 display: table-cell;
1932 1932 min-width: @label-summary-minwidth;
1933 1933 padding-top: @padding/2;
1934 1934 padding-bottom: @padding/2;
1935 1935 padding-right: @padding/2;
1936 1936 }
1937 1937
1938 1938 .input{
1939 1939 display: table-cell;
1940 1940 padding: @padding/2;
1941 1941
1942 1942 input{
1943 1943 min-width: 29em;
1944 1944 padding: @padding/4;
1945 1945 }
1946 1946 }
1947 1947 .statistics, .downloads{
1948 1948 .disabled{
1949 1949 color: @grey4;
1950 1950 }
1951 1951 }
1952 1952 }
1953 1953 }
1954 1954
1955 1955 #summary{
1956 1956 width: 70%;
1957 1957 }
1958 1958
1959 1959
1960 1960 // Journal
1961 1961 .journal.title {
1962 1962 h5 {
1963 1963 float: left;
1964 1964 margin: 0;
1965 1965 width: 70%;
1966 1966 }
1967 1967
1968 1968 ul {
1969 1969 float: right;
1970 1970 display: inline-block;
1971 1971 margin: 0;
1972 1972 width: 30%;
1973 1973 text-align: right;
1974 1974
1975 1975 li {
1976 1976 display: inline;
1977 1977 font-size: @journal-fontsize;
1978 1978 line-height: 1em;
1979 1979
1980 1980 list-style-type: none;
1981 1981 }
1982 1982 }
1983 1983 }
1984 1984
1985 1985 .filterexample {
1986 1986 position: absolute;
1987 1987 top: 95px;
1988 1988 left: @contentpadding;
1989 1989 color: @rcblue;
1990 1990 font-size: 11px;
1991 1991 font-family: @text-regular;
1992 1992 cursor: help;
1993 1993
1994 1994 &:hover {
1995 1995 color: @rcdarkblue;
1996 1996 }
1997 1997
1998 1998 @media (max-width:768px) {
1999 1999 position: relative;
2000 2000 top: auto;
2001 2001 left: auto;
2002 2002 display: block;
2003 2003 }
2004 2004 }
2005 2005
2006 2006
2007 2007 #journal{
2008 2008 margin-bottom: @space;
2009 2009
2010 2010 .journal_day{
2011 2011 margin-bottom: @textmargin/2;
2012 2012 padding-bottom: @textmargin/2;
2013 2013 font-size: @journal-fontsize;
2014 2014 border-bottom: @border-thickness solid @border-default-color;
2015 2015 }
2016 2016
2017 2017 .journal_container{
2018 2018 margin-bottom: @space;
2019 2019
2020 2020 .journal_user{
2021 2021 display: inline-block;
2022 2022 }
2023 2023 .journal_action_container{
2024 2024 display: block;
2025 2025 margin-top: @textmargin;
2026 2026
2027 2027 div{
2028 2028 display: inline;
2029 2029 }
2030 2030
2031 2031 div.journal_action_params{
2032 2032 display: block;
2033 2033 }
2034 2034
2035 2035 div.journal_repo:after{
2036 2036 content: "\A";
2037 2037 white-space: pre;
2038 2038 }
2039 2039
2040 2040 div.date{
2041 2041 display: block;
2042 2042 margin-bottom: @textmargin;
2043 2043 }
2044 2044 }
2045 2045 }
2046 2046 }
2047 2047
2048 2048 // Files
2049 2049 .edit-file-title {
2050 2050 border-bottom: @border-thickness solid @border-default-color;
2051 2051
2052 2052 .breadcrumbs {
2053 2053 margin-bottom: 0;
2054 2054 }
2055 2055 }
2056 2056
2057 2057 .edit-file-fieldset {
2058 2058 margin-top: @sidebarpadding;
2059 2059
2060 2060 .fieldset {
2061 2061 .left-label {
2062 2062 width: 13%;
2063 2063 }
2064 2064 .right-content {
2065 2065 width: 87%;
2066 2066 max-width: 100%;
2067 2067 }
2068 2068 .filename-label {
2069 2069 margin-top: 13px;
2070 2070 }
2071 2071 .commit-message-label {
2072 2072 margin-top: 4px;
2073 2073 }
2074 2074 .file-upload-input {
2075 2075 input {
2076 2076 display: none;
2077 2077 }
2078 2078 margin-top: 10px;
2079 2079 }
2080 2080 .file-upload-label {
2081 2081 margin-top: 10px;
2082 2082 }
2083 2083 p {
2084 2084 margin-top: 5px;
2085 2085 }
2086 2086
2087 2087 }
2088 2088 .custom-path-link {
2089 2089 margin-left: 5px;
2090 2090 }
2091 2091 #commit {
2092 2092 resize: vertical;
2093 2093 }
2094 2094 }
2095 2095
2096 2096 .delete-file-preview {
2097 2097 max-height: 250px;
2098 2098 }
2099 2099
2100 2100 .new-file,
2101 2101 #filter_activate,
2102 2102 #filter_deactivate {
2103 2103 float: right;
2104 2104 margin: 0 0 0 10px;
2105 2105 }
2106 2106
2107 2107 h3.files_location{
2108 2108 line-height: 2.4em;
2109 2109 }
2110 2110
2111 2111 .browser-nav {
2112 2112 width: 100%;
2113 2113 display: table;
2114 2114 margin-bottom: 20px;
2115 2115
2116 2116 .info_box {
2117 2117 float: left;
2118 2118 display: inline-table;
2119 2119 height: 2.5em;
2120 2120
2121 2121 .browser-cur-rev, .info_box_elem {
2122 2122 display: table-cell;
2123 2123 vertical-align: middle;
2124 2124 }
2125 2125
2126 2126 .drop-menu {
2127 2127 margin: 0 10px;
2128 2128 }
2129 2129
2130 2130 .info_box_elem {
2131 2131 border-top: @border-thickness solid @grey5;
2132 2132 border-bottom: @border-thickness solid @grey5;
2133 2133 box-shadow: @button-shadow;
2134 2134
2135 2135 #at_rev, a {
2136 2136 padding: 0.6em 0.4em;
2137 2137 margin: 0;
2138 2138 .box-shadow(none);
2139 2139 border: 0;
2140 2140 height: 12px;
2141 2141 color: @grey2;
2142 2142 }
2143 2143
2144 2144 input#at_rev {
2145 2145 max-width: 50px;
2146 2146 text-align: center;
2147 2147 }
2148 2148
2149 2149 &.previous {
2150 2150 border: @border-thickness solid @grey5;
2151 2151 border-top-left-radius: @border-radius;
2152 2152 border-bottom-left-radius: @border-radius;
2153 2153
2154 2154 &:hover {
2155 2155 border-color: @grey4;
2156 2156 }
2157 2157
2158 2158 .disabled {
2159 2159 color: @grey5;
2160 2160 cursor: not-allowed;
2161 2161 opacity: 0.5;
2162 2162 }
2163 2163 }
2164 2164
2165 2165 &.next {
2166 2166 border: @border-thickness solid @grey5;
2167 2167 border-top-right-radius: @border-radius;
2168 2168 border-bottom-right-radius: @border-radius;
2169 2169
2170 2170 &:hover {
2171 2171 border-color: @grey4;
2172 2172 }
2173 2173
2174 2174 .disabled {
2175 2175 color: @grey5;
2176 2176 cursor: not-allowed;
2177 2177 opacity: 0.5;
2178 2178 }
2179 2179 }
2180 2180 }
2181 2181
2182 2182 .browser-cur-rev {
2183 2183
2184 2184 span{
2185 2185 margin: 0;
2186 2186 color: @rcblue;
2187 2187 height: 12px;
2188 2188 display: inline-block;
2189 2189 padding: 0.7em 1em ;
2190 2190 border: @border-thickness solid @rcblue;
2191 2191 margin-right: @padding;
2192 2192 }
2193 2193 }
2194 2194
2195 }
2196
2195 2197 .select-index-number {
2196 2198 margin: 0 0 0 20px;
2197 2199 color: @grey3;
2198 2200 }
2199 }
2200 2201
2201 2202 .search_activate {
2202 2203 display: table-cell;
2203 2204 vertical-align: middle;
2204 2205
2205 2206 input, label{
2206 2207 margin: 0;
2207 2208 padding: 0;
2208 2209 }
2209 2210
2210 2211 input{
2211 2212 margin-left: @textmargin;
2212 2213 }
2213 2214
2214 2215 }
2215 2216 }
2216 2217
2217 2218 .browser-cur-rev{
2218 2219 margin-bottom: @textmargin;
2219 2220 }
2220 2221
2221 2222 #node_filter_box_loading{
2222 2223 .info_text;
2223 2224 }
2224 2225
2225 2226 .browser-search {
2226 2227 margin: -25px 0px 5px 0px;
2227 2228 }
2228 2229
2229 2230 .files-quick-filter {
2230 2231 float: right;
2231 2232 width: 180px;
2232 2233 position: relative;
2233 2234 }
2234 2235
2235 2236 .files-filter-box {
2236 2237 display: flex;
2237 2238 padding: 0px;
2238 2239 border-radius: 3px;
2239 2240 margin-bottom: 0;
2240 2241
2241 2242 a {
2242 2243 border: none !important;
2243 2244 }
2244 2245
2245 2246 li {
2246 2247 list-style-type: none
2247 2248 }
2248 2249 }
2249 2250
2250 2251 .files-filter-box-path {
2251 2252 line-height: 33px;
2252 2253 padding: 0;
2253 2254 width: 20px;
2254 2255 position: absolute;
2255 2256 z-index: 11;
2256 2257 left: 5px;
2257 2258 }
2258 2259
2259 2260 .files-filter-box-input {
2260 2261 margin-right: 0;
2261 2262
2262 2263 input {
2263 2264 border: 1px solid @white;
2264 2265 padding-left: 25px;
2265 2266 width: 145px;
2266 2267
2267 2268 &:hover {
2268 2269 border-color: @grey6;
2269 2270 }
2270 2271
2271 2272 &:focus {
2272 2273 border-color: @grey5;
2273 2274 }
2274 2275 }
2275 2276 }
2276 2277
2277 2278 .browser-result{
2278 2279 td a{
2279 2280 margin-left: 0.5em;
2280 2281 display: inline-block;
2281 2282
2282 2283 em {
2283 2284 font-weight: @text-bold-weight;
2284 2285 font-family: @text-bold;
2285 2286 }
2286 2287 }
2287 2288 }
2288 2289
2289 2290 .browser-highlight{
2290 2291 background-color: @grey5-alpha;
2291 2292 }
2292 2293
2293 2294
2294 2295 // Search
2295 2296
2296 2297 .search-form{
2297 2298 #q {
2298 2299 width: @search-form-width;
2299 2300 }
2300 2301 .fields{
2301 2302 margin: 0 0 @space;
2302 2303 }
2303 2304
2304 2305 label{
2305 2306 display: inline-block;
2306 2307 margin-right: @textmargin;
2307 2308 padding-top: 0.25em;
2308 2309 }
2309 2310
2310 2311
2311 2312 .results{
2312 2313 clear: both;
2313 2314 margin: 0 0 @padding;
2314 2315 }
2315 2316
2316 2317 .search-tags {
2317 2318 padding: 5px 0;
2318 2319 }
2319 2320 }
2320 2321
2321 2322 div.search-feedback-items {
2322 2323 display: inline-block;
2323 2324 }
2324 2325
2325 2326 div.search-code-body {
2326 2327 background-color: #ffffff; padding: 5px 0 5px 10px;
2327 2328 pre {
2328 2329 .match { background-color: #faffa6;}
2329 2330 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2330 2331 }
2331 2332 }
2332 2333
2333 2334 .expand_commit.search {
2334 2335 .show_more.open {
2335 2336 height: auto;
2336 2337 max-height: none;
2337 2338 }
2338 2339 }
2339 2340
2340 2341 .search-results {
2341 2342
2342 2343 h2 {
2343 2344 margin-bottom: 0;
2344 2345 }
2345 2346 .codeblock {
2346 2347 border: none;
2347 2348 background: transparent;
2348 2349 }
2349 2350
2350 2351 .codeblock-header {
2351 2352 border: none;
2352 2353 background: transparent;
2353 2354 }
2354 2355
2355 2356 .code-body {
2356 2357 border: @border-thickness solid @border-default-color;
2357 2358 .border-radius(@border-radius);
2358 2359 }
2359 2360
2360 2361 .td-commit {
2361 2362 &:extend(pre);
2362 2363 border-bottom: @border-thickness solid @border-default-color;
2363 2364 }
2364 2365
2365 2366 .message {
2366 2367 height: auto;
2367 2368 max-width: 350px;
2368 2369 white-space: normal;
2369 2370 text-overflow: initial;
2370 2371 overflow: visible;
2371 2372
2372 2373 .match { background-color: #faffa6;}
2373 2374 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2374 2375 }
2375 2376
2376 2377 }
2377 2378
2378 2379 table.rctable td.td-search-results div {
2379 2380 max-width: 100%;
2380 2381 }
2381 2382
2382 2383 #tip-box, .tip-box{
2383 2384 padding: @menupadding/2;
2384 2385 display: block;
2385 2386 border: @border-thickness solid @border-highlight-color;
2386 2387 .border-radius(@border-radius);
2387 2388 background-color: white;
2388 2389 z-index: 99;
2389 2390 white-space: pre-wrap;
2390 2391 }
2391 2392
2392 2393 #linktt {
2393 2394 width: 79px;
2394 2395 }
2395 2396
2396 2397 #help_kb .modal-content{
2397 2398 max-width: 750px;
2398 2399 margin: 10% auto;
2399 2400
2400 2401 table{
2401 2402 td,th{
2402 2403 border-bottom: none;
2403 2404 line-height: 2.5em;
2404 2405 }
2405 2406 th{
2406 2407 padding-bottom: @textmargin/2;
2407 2408 }
2408 2409 td.keys{
2409 2410 text-align: center;
2410 2411 }
2411 2412 }
2412 2413
2413 2414 .block-left{
2414 2415 width: 45%;
2415 2416 margin-right: 5%;
2416 2417 }
2417 2418 .modal-footer{
2418 2419 clear: both;
2419 2420 }
2420 2421 .key.tag{
2421 2422 padding: 0.5em;
2422 2423 background-color: @rcblue;
2423 2424 color: white;
2424 2425 border-color: @rcblue;
2425 2426 .box-shadow(none);
2426 2427 }
2427 2428 }
2428 2429
2429 2430
2430 2431
2431 2432 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2432 2433
2433 2434 @import 'statistics-graph';
2434 2435 @import 'tables';
2435 2436 @import 'forms';
2436 2437 @import 'diff';
2437 2438 @import 'summary';
2438 2439 @import 'navigation';
2439 2440
2440 2441 //--- SHOW/HIDE SECTIONS --//
2441 2442
2442 2443 .btn-collapse {
2443 2444 float: right;
2444 2445 text-align: right;
2445 2446 font-family: @text-light;
2446 2447 font-size: @basefontsize;
2447 2448 cursor: pointer;
2448 2449 border: none;
2449 2450 color: @rcblue;
2450 2451 }
2451 2452
2452 2453 table.rctable,
2453 2454 table.dataTable {
2454 2455 .btn-collapse {
2455 2456 float: right;
2456 2457 text-align: right;
2457 2458 }
2458 2459 }
2459 2460
2460 2461 table.rctable {
2461 2462 &.permissions {
2462 2463
2463 2464 th.td-owner {
2464 2465 padding: 0;
2465 2466 }
2466 2467
2467 2468 th {
2468 2469 font-weight: normal;
2469 2470 padding: 0 5px;
2470 2471 }
2471 2472
2472 2473 }
2473 2474 }
2474 2475
2475 2476
2476 2477 // TODO: johbo: Fix for IE10, this avoids that we see a border
2477 2478 // and padding around checkboxes and radio boxes. Move to the right place,
2478 2479 // or better: Remove this once we did the form refactoring.
2479 2480 input[type=checkbox],
2480 2481 input[type=radio] {
2481 2482 padding: 0;
2482 2483 border: none;
2483 2484 }
2484 2485
2485 2486 .toggle-ajax-spinner{
2486 2487 height: 16px;
2487 2488 width: 16px;
2488 2489 }
2489 2490
2490 2491
2491 2492 .markup-form .clearfix {
2492 2493 .border-radius(@border-radius);
2493 2494 margin: 0px;
2494 2495 }
2495 2496
2496 2497 .markup-form-area {
2497 2498 padding: 8px 12px;
2498 2499 border: 1px solid @grey4;
2499 2500 .border-radius(@border-radius);
2500 2501 }
2501 2502
2502 2503 .markup-form-area-header .nav-links {
2503 2504 display: flex;
2504 2505 flex-flow: row wrap;
2505 2506 -webkit-flex-flow: row wrap;
2506 2507 width: 100%;
2507 2508 }
2508 2509
2509 2510 .markup-form-area-footer {
2510 2511 display: flex;
2511 2512 }
2512 2513
2513 2514 .markup-form-area-footer .toolbar {
2514 2515
2515 2516 }
2516 2517
2517 2518 // markup Form
2518 2519 div.markup-form {
2519 2520 margin-top: 20px;
2520 2521 }
2521 2522
2522 2523 .markup-form strong {
2523 2524 display: block;
2524 2525 margin-bottom: 15px;
2525 2526 }
2526 2527
2527 2528 .markup-form textarea {
2528 2529 width: 100%;
2529 2530 height: 100px;
2530 2531 font-family: @text-monospace;
2531 2532 }
2532 2533
2533 2534 form.markup-form {
2534 2535 margin-top: 10px;
2535 2536 margin-left: 10px;
2536 2537 }
2537 2538
2538 2539 .markup-form .comment-block-ta,
2539 2540 .markup-form .preview-box {
2540 2541 .border-radius(@border-radius);
2541 2542 .box-sizing(border-box);
2542 2543 background-color: white;
2543 2544 }
2544 2545
2545 2546 .markup-form .preview-box.unloaded {
2546 2547 height: 50px;
2547 2548 text-align: center;
2548 2549 padding: 20px;
2549 2550 background-color: white;
2550 2551 }
2551 2552
2552 2553 .dropzone {
2553 2554 border: 2px dashed @rcdarkblue;
2554 2555 border-radius: 5px;
2555 2556 background: white;
2556 2557 min-height: 200px;
2557 2558 padding: 54px;
2558 2559 }
2559 2560 .dropzone .dz-message {
2560 2561 font-weight: 700;
2561 2562 }
2562 2563
2563 2564 .dropzone .dz-message {
2564 2565 text-align: center;
2565 2566 margin: 2em 0;
2566 2567 }
2567 2568
2568 2569 .dz-preview {
2569 2570 margin: 10px -40px !important;
2570 2571 position: relative;
2571 2572 vertical-align: top;
2572 2573 border: 1px solid @grey4;
2573 2574 border-radius: 5px;
2574 2575 padding: 10px;
2575 2576 }
2576 2577
2577 2578 .dz-filename {
2578 2579 font-weight: 700;
2579 2580 }
2580 2581
2581 2582 .dz-error-message {
2582 2583 color: @alert2;
2583 2584 } No newline at end of file
@@ -1,273 +1,274 b''
1 1 @font-face {
2 2 font-family: 'rcicons';
3 3
4 src: url('../fonts/RCIcons/rcicons.eot?73199028');
5 src: url('../fonts/RCIcons/rcicons.eot?73199028#iefix') format('embedded-opentype'),
6 url('../fonts/RCIcons/rcicons.woff2?73199028') format('woff2'),
7 url('../fonts/RCIcons/rcicons.woff?73199028') format('woff'),
8 url('../fonts/RCIconst/rcicons.ttf?73199028') format('truetype'),
9 url('../fonts/RCIcons/rcicons.svg?73199028#rcicons') format('svg');
4 src: url('../fonts/RCIcons/rcicons.eot?9641970');
5 src: url('../fonts/RCIcons/rcicons.eot?9641970#iefix') format('embedded-opentype'),
6 url('../fonts/RCIcons/rcicons.woff2?9641970') format('woff2'),
7 url('../fonts/RCIcons/rcicons.woff?9641970') format('woff'),
8 url('../fonts/RCIcons/rcicons.ttf?9641970') format('truetype'),
9 url('../fonts/RCIcons/rcicons.svg?9641970#rcicons') format('svg');
10 10
11 11 font-weight: normal;
12 12 font-style: normal;
13 13 }
14 14 /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
15 15 /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
16 16 /*
17 17 @media screen and (-webkit-min-device-pixel-ratio:0) {
18 18 @font-face {
19 19 font-family: 'rcicons';
20 20 src: url('../fonts/RCIcons/rcicons.svg?74666722#rcicons') format('svg');
21 21 }
22 22 }
23 23 */
24 24
25 25 [class^="icon-"]:before, [class*=" icon-"]:before {
26 26 font-family: "rcicons";
27 27 font-style: normal;
28 28 font-weight: normal;
29 29 speak: none;
30 30
31 31 display: inline-block;
32 32 text-decoration: inherit;
33 33 width: 1em;
34 34 margin-right: .2em;
35 35 text-align: center;
36 36 /* opacity: .8; */
37 37
38 38 /* For safety - reset parent styles, that can break glyph codes*/
39 39 font-variant: normal;
40 40 text-transform: none;
41 41
42 42 /* fix buttons height, for twitter bootstrap */
43 43 line-height: 1em;
44 44
45 45 /* Animation center compensation - margins should be symmetric */
46 46 /* remove if not needed */
47 47 margin-left: .2em;
48 48
49 49 /* you can be more comfortable with increased icons size */
50 50 /* font-size: 120%; */
51 51
52 52 /* Font smoothing. That was taken from TWBS */
53 53 -webkit-font-smoothing: antialiased;
54 54 -moz-osx-font-smoothing: grayscale;
55 55
56 56 /* Uncomment for 3D effect */
57 57 /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
58 58 }
59 59
60 60 .animate-spin {
61 61 -moz-animation: spin 2s infinite linear;
62 62 -o-animation: spin 2s infinite linear;
63 63 -webkit-animation: spin 2s infinite linear;
64 64 animation: spin 2s infinite linear;
65 65 display: inline-block;
66 66 }
67 67 @-moz-keyframes spin {
68 68 0% {
69 69 -moz-transform: rotate(0deg);
70 70 -o-transform: rotate(0deg);
71 71 -webkit-transform: rotate(0deg);
72 72 transform: rotate(0deg);
73 73 }
74 74
75 75 100% {
76 76 -moz-transform: rotate(359deg);
77 77 -o-transform: rotate(359deg);
78 78 -webkit-transform: rotate(359deg);
79 79 transform: rotate(359deg);
80 80 }
81 81 }
82 82 @-webkit-keyframes spin {
83 83 0% {
84 84 -moz-transform: rotate(0deg);
85 85 -o-transform: rotate(0deg);
86 86 -webkit-transform: rotate(0deg);
87 87 transform: rotate(0deg);
88 88 }
89 89
90 90 100% {
91 91 -moz-transform: rotate(359deg);
92 92 -o-transform: rotate(359deg);
93 93 -webkit-transform: rotate(359deg);
94 94 transform: rotate(359deg);
95 95 }
96 96 }
97 97 @-o-keyframes spin {
98 98 0% {
99 99 -moz-transform: rotate(0deg);
100 100 -o-transform: rotate(0deg);
101 101 -webkit-transform: rotate(0deg);
102 102 transform: rotate(0deg);
103 103 }
104 104
105 105 100% {
106 106 -moz-transform: rotate(359deg);
107 107 -o-transform: rotate(359deg);
108 108 -webkit-transform: rotate(359deg);
109 109 transform: rotate(359deg);
110 110 }
111 111 }
112 112 @-ms-keyframes spin {
113 113 0% {
114 114 -moz-transform: rotate(0deg);
115 115 -o-transform: rotate(0deg);
116 116 -webkit-transform: rotate(0deg);
117 117 transform: rotate(0deg);
118 118 }
119 119
120 120 100% {
121 121 -moz-transform: rotate(359deg);
122 122 -o-transform: rotate(359deg);
123 123 -webkit-transform: rotate(359deg);
124 124 transform: rotate(359deg);
125 125 }
126 126 }
127 127 @keyframes spin {
128 128 0% {
129 129 -moz-transform: rotate(0deg);
130 130 -o-transform: rotate(0deg);
131 131 -webkit-transform: rotate(0deg);
132 132 transform: rotate(0deg);
133 133 }
134 134
135 135 100% {
136 136 -moz-transform: rotate(359deg);
137 137 -o-transform: rotate(359deg);
138 138 -webkit-transform: rotate(359deg);
139 139 transform: rotate(359deg);
140 140 }
141 141 }
142 142
143 143
144 144
145 145 .icon-no-margin::before {
146 146 margin: 0;
147 147
148 148 }
149 149 // -- ICON CLASSES -- //
150 150 // sorter = lambda s: '\n'.join(sorted(s.splitlines()))
151 151
152 152 .icon-delete:before { content: '\e800'; } /* '' */
153 153 .icon-ok:before { content: '\e801'; } /* '' */
154 154 .icon-comment:before { content: '\e802'; } /* '' */
155 155 .icon-bookmark:before { content: '\e803'; } /* '' */
156 156 .icon-branch:before { content: '\e804'; } /* '' */
157 157 .icon-tag:before { content: '\e805'; } /* '' */
158 158 .icon-lock:before { content: '\e806'; } /* '' */
159 159 .icon-unlock:before { content: '\e807'; } /* '' */
160 160 .icon-feed:before { content: '\e808'; } /* '' */
161 161 .icon-left:before { content: '\e809'; } /* '' */
162 162 .icon-right:before { content: '\e80a'; } /* '' */
163 163 .icon-down:before { content: '\e80b'; } /* '' */
164 164 .icon-folder:before { content: '\e80c'; } /* '' */
165 165 .icon-folder-open:before { content: '\e80d'; } /* '' */
166 166 .icon-folder-empty:before { content: '\f114'; } /* '' */
167 167 .icon-folder-open-empty:before { content: '\f115'; } /* '' */
168 168 .icon-trash-empty:before { content: '\e80e'; } /* '' */
169 169 .icon-group:before { content: '\e80f'; } /* '' */
170 170 .icon-remove:before { content: '\e810'; } /* '' */
171 171 .icon-fork:before { content: '\e811'; } /* '' */
172 172 .icon-more:before { content: '\e812'; } /* '' */
173 173 .icon-search:before { content: '\e813'; } /* '' */
174 174 .icon-scissors:before { content: '\e814'; } /* '' */
175 175 .icon-download:before { content: '\e815'; } /* '' */
176 176 .icon-doc:before { content: '\e816'; } /* '' */
177 177 .icon-cog:before { content: '\e817'; } /* '' */
178 178 .icon-cog-alt:before { content: '\e818'; } /* '' */
179 179 .icon-eye:before { content: '\e819'; } /* '' */
180 180 .icon-eye-off:before { content: '\e81a'; } /* '' */
181 181 .icon-cancel-circled2:before { content: '\e81b'; } /* '' */
182 182 .icon-cancel-circled:before { content: '\e81c'; } /* '' */
183 183 .icon-plus:before { content: '\e81d'; } /* '' */
184 184 .icon-plus-circled:before { content: '\e81e'; } /* '' */
185 185 .icon-minus-circled:before { content: '\e81f'; } /* '' */
186 186 .icon-minus:before { content: '\e820'; } /* '' */
187 187 .icon-info-circled:before { content: '\e821'; } /* '' */
188 188 .icon-upload:before { content: '\e822'; } /* '' */
189 .icon-home:before { content: '\e823'; } /* '' */
189 190 .icon-git:before { content: '\e82a'; } /* '' */
190 191 .icon-hg:before { content: '\e82d'; } /* '' */
191 192 .icon-svn:before { content: '\e82e'; } /* '' */
192 193 .icon-comment-add:before { content: '\e82f'; } /* '' */
193 194 .icon-comment-toggle:before { content: '\e830'; } /* '' */
194 195 .icon-rhodecode:before { content: '\e831'; } /* '' */
195 196 .icon-up:before { content: '\e832'; } /* '' */
196 197 .icon-merge:before { content: '\e833'; } /* '' */
197 198 .icon-docs:before { content: '\f0c5'; } /* '' */
198 199 .icon-menu:before { content: '\f0c9'; } /* '' */
199 200 .icon-paste:before { content: '\f0ea'; } /* '' */
200 201 .icon-doc-text:before { content: '\f0f6'; } /* '' */
201 202 .icon-plus-squared:before { content: '\f0fe'; } /* '' */
202 203 .icon-minus-squared:before { content: '\f146'; } /* '' */
203 204 .icon-minus-squared-alt:before { content: '\f147'; } /* '' */
204 205 .icon-doc-inv:before { content: '\f15b'; } /* '' */
205 206 .icon-doc-text-inv:before { content: '\f15c'; } /* '' */
206 207 .icon-plus-squared-alt:before { content: '\f196'; } /* '' */
207 208 .icon-file-code:before { content: '\f1c9'; } /* '' */
208 209 .icon-sliders:before { content: '\f1de'; } /* '' */
209 210 .icon-trash:before { content: '\f1f8'; } /* '' */
210 211 .icon-spin-alt:before { content: '\e834'; } /* '' */
211 212 .icon-spin:before { content: '\e838'; } /* '' */
212 213
213 214
214 215 // MERGED ICONS BASED ON CURRENT ONES
215 216 .icon-repo-group:before { &:extend(.icon-folder-open:before); }
216 217 .icon-repo-private:before { &:extend(.icon-lock:before); }
217 218 .icon-repo-lock:before { &:extend(.icon-lock:before); }
218 219 .icon-unlock-alt:before { &:extend(.icon-unlock:before); }
219 220 .icon-repo-unlock:before { &:extend(.icon-unlock:before); }
220 221 .icon-repo-public:before { &:extend(.icon-unlock:before); }
221 222 .icon-rss-sign:before { &:extend(.icon-feed:before); }
222 223 .icon-code-fork:before { &:extend(.icon-fork:before); }
223 224 .icon-arrow_up:before { &:extend(.icon-up:before); }
224 225 .icon-file:before { &:extend(.icon-file-code:before); }
225 226 .icon-file-text:before { &:extend(.icon-file-code:before); }
226 227 .icon-directory:before { &:extend(.icon-folder:before); }
227 228 .icon-more-linked:before { &:extend(.icon-more:before); }
228 229 .icon-clipboard:before { &:extend(.icon-docs:before); }
229 230 .icon-copy:before { &:extend(.icon-docs:before); }
230 231 .icon-true:before { &:extend(.icon-ok:before); }
231 232 .icon-false:before { &:extend(.icon-delete:before); }
232 233 .icon-expand-linked:before { &:extend(.icon-down:before); }
233 234 .icon-pr-merge-fail:before { &:extend(.icon-delete:before); }
234 235
235 236 // TRANSFORM
236 237
237 238 .icon-merge:before {transform: rotate(180deg);}
238 239
239 240 // -- END ICON CLASSES -- //
240 241
241 242
242 243 //--- ICONS STYLING ------------------//
243 244
244 245 .icon-git { color: @color4 !important; }
245 246 .icon-hg { color: @color8 !important; }
246 247 .icon-svn { color: @color1 !important; }
247 248 .icon-git-inv { color: @color4 !important; }
248 249 .icon-hg-inv { color: @color8 !important; }
249 250 .icon-svn-inv { color: @color1 !important; }
250 251 .icon-repo-lock { color: #FF0000; }
251 252 .icon-repo-unlock { color: #FF0000; }
252 253 .icon-false { color: @grey5 }
253 254 .icon-expand-linked { cursor: pointer; color: @grey3; font-size: 14px }
254 255 .icon-more-linked { cursor: pointer; color: @grey3 }
255 256
256 257 .repo-switcher-dropdown .select2-result-label {
257 258 .icon-git:before {
258 259 &:extend(.icon-git-transparent:before);
259 260 }
260 261 .icon-hg:before {
261 262 &:extend(.icon-hg-transparent:before);
262 263 color: @alert4;
263 264 }
264 265 .icon-svn:before {
265 266 &:extend(.icon-svn-transparent:before);
266 267 }
267 268 }
268 269
269 270 .icon-user-group:before {
270 271 &:extend(.icon-group:before);
271 272 margin: 0;
272 273 font-size: 16px;
273 274 }
@@ -1,478 +1,476 b''
1 1 // summary.less
2 2 // For use in RhodeCode applications;
3 3 // Used for headers and file detail summary screens.
4 4
5 5 .summary {
6 6 clear: both;
7 7 float: none;
8 8 position: relative;
9 9 width: 100%;
10 10 margin: 0;
11 11 padding: 0;
12 12 background: #FCFCFC;
13 13 border: 1px solid #EAEAEA;
14 14 border-radius: @border-radius;
15 15 margin-bottom: 20px;
16 16
17 17 .summary-detail-header {
18 18 display: block;
19 19 width: 100%;
20 20 margin-bottom: 10px;
21 21 padding: 0 0 .5em 0;
22 22 border-bottom: @border-thickness solid @border-default-color;
23 23
24 24 .breadcrumbs {
25 25 display: inline;
26 26 margin: 0;
27 27 padding: 0;
28 28 }
29 29
30 30 h4 {
31 31 margin: 0 1em 0 0;
32 32 padding: 10px 0 5px 20px;
33 33 line-height: 1.2em;
34 34 font-size: @basefontsize;
35 35 }
36 36
37 37 .action_link {
38 38 float: right;
39 39 }
40 40
41 41 .new-file {
42 42 float: right;
43 43 margin-top: -1.5em;
44 44 }
45 45 }
46 46
47 47 .summary-detail {
48 48 float: none;
49 49 position: relative;
50 50 width: 100%;
51 51 margin: 0;
52 52 padding: 0 0 20px 0;
53 53
54 54 .file_diff_buttons {
55 55 margin-top: @space;
56 56 }
57 57
58 58 // commit message
59 59 .commit {
60 60 white-space: pre-wrap;
61 61 }
62 62
63 63 .left-clone {
64 64 float: left;
65 65 height: 30px;
66 66 margin: 0;
67 67 padding: 0;
68 68 width: 130px;
69 69 font-weight: @text-semibold-weight;
70 70 font-family: @text-semibold;
71 71 }
72 72 .left-clone select {
73 73 width: 130px;
74 74 margin-right: 0;
75 75 background-color: @grey7;
76 76 border-color: @grey4;
77 77 color: #5C5C5C;
78 78 border-top-right-radius: 0;
79 79 border-bottom-right-radius: 0;
80 80 }
81 81
82 82 .right-clone {
83 83 float: left;
84 84 width: ~"calc(100% - 170px)";
85 85
86 86 .clipboard-action {
87 87 margin-left: -30px;
88 88 }
89 89 }
90 90
91 91 .clone_url_input {
92 92 width: ~"calc(100% - 90px)";
93 93 padding: 6px 30px 6px 10px;
94 94 height: 14px;
95 95 box-shadow: 0 1px 1px 0 rgba(0,0,0,0.07);
96 96 border-top-left-radius: 0;
97 97 border-bottom-left-radius: 0;
98 98 margin-left: -1px;
99 99 }
100 100
101 101 &.directory {
102 102 margin-bottom: 0;
103 103 }
104 104
105 105 .desc {
106 106 white-space: pre-wrap;
107 107 }
108 108 .disabled {
109 109 opacity: .5;
110 110 cursor: inherit;
111 111 }
112 112 .help-block {
113 113 color: inherit;
114 114 margin: 0;
115 115 }
116 116 }
117 117
118 118 .sidebar-right {
119 119 float: left;
120 120 width: 24%;
121 121 margin: 0;
122 122 padding: 0;
123 123
124 124 ul {
125 125 margin-left: 0;
126 126 padding-left: 0;
127 127
128 128 li {
129 129 list-style-type: none;
130 130 }
131 131 }
132 132 }
133 133
134 134 #clone_by_name, #clone_by_id{
135 135 display: inline-block;
136 136 margin-left: 0px;
137 137 }
138 138
139 139 .codeblock {
140 140 border: none;
141 141 background-color: transparent;
142 142 }
143 143
144 144 .code-body {
145 145 border: @border-thickness solid @border-default-color;
146 146 .border-radius(@border-radius);
147 147 }
148 148
149 149 .btn-collapse {
150 150 clear: both;
151 151 float: none;
152 152 background: #F7F7F7;
153 153 text-align: center;
154 154 color: #949494;
155 155 font-size: 11px;
156 156
157 157 &:hover {
158 158 background: #f1f1f1;
159 159 color: #2B2B2D;
160 160 }
161 161 }
162 162 }
163 163
164 164 // this is used outside of just the summary
165 165 .fieldset, // similar to form fieldset
166 166 .summary .sidebar-right-content { // these have to match
167 167 clear: both;
168 168 float: none;
169 169 position: relative;
170 170 display:block;
171 171 width: 100%;
172 172 min-height: 1em;
173 173 margin-bottom: 10px;
174 174 padding: 0;
175 175 line-height: 1.2em;
176 176
177 177 &:after { // clearfix
178 178 content: "";
179 179 clear: both;
180 180 width: 100%;
181 181 height: 1em;
182 182 }
183 183 }
184 184
185 185 .summary .sidebar-right-content {
186 186 margin-bottom: 0;
187 187
188 188 .rc-user {
189 189 min-width: 0;
190 190 }
191 191
192 192 li {
193 193 list-style: none;
194 194 line-height: normal;
195 195 }
196 196 }
197 197
198 198 .summary {
199 199 .fieldset {
200 200 margin-bottom: 0;
201 201 }
202 202 }
203 203
204 204 .fieldset {
205 205
206 206 .left-label { // similar to form legend
207 207 display: block;
208 208 margin: 0;
209 209 padding: 0;
210 210 font-weight: @text-semibold-weight;
211 211 font-family: @text-semibold;
212 212 }
213 213
214 214 .left-label-summary {
215 215 padding-left: 20px;
216 216 margin-bottom: 5px;
217 217
218 218 p {
219 219 margin-bottom: 5px;
220 220 color: @grey1;
221 221 float: left;
222 222 width: 130px;
223 223
224 224 &.spacing {
225 225 margin-top: 10px;
226 226 }
227 227 }
228 228
229 229 .right-label-summary {
230 230 float: left;
231 231 margin-top: 7px;
232 232 width: ~"calc(100% - 160px)";
233 233 }
234 234 }
235 235
236 236 .left-label-summary-files {
237 237 padding-left: 45px;
238 238 margin-top: 5px;
239 239
240 240 p {
241 241 margin-bottom: 5px;
242 242 color: @grey1;
243 243 float: left;
244 244 width: 130px;
245 245
246 246 &.spacing {
247 247 margin-top: 10px;
248 248 }
249 249 }
250 250
251 251 .right-label-summary {
252 252 float: left;
253 253 margin-top: 7px;
254 254 }
255 255 }
256 256
257 257 .left-content {
258 258 width: ~"calc(60% - 20px)";
259 259 float: left;
260 260 margin: 15px 0 15px 20px;
261 261
262 262 .rc-user {
263 263 min-width: auto;
264 264 max-width: none;
265 265 min-height: auto;
266 266 padding-right: 5px;
267 267 }
268 268
269 269 .left-content-avatar {
270 270 width: 45px;
271 271 float: left;
272 272 margin-top: 8px;
273 273 }
274 274
275 275 .left-content-message {
276 276 float: left;
277 277 width: ~"calc(100% - 45px)";
278 278 }
279 279 }
280 280
281 281 .right-content { // similar to form fields
282 282 float: left;
283 283 display: block;
284 284 width: ~"calc(40% - 20px)";
285 285 text-align: right;
286 286 margin: 15px 20px 15px 0;
287 287
288 288 .truncate-wrap,
289 289 .truncate {
290 290 max-width: 100%;
291 291 width: 100%;
292 292 }
293 293
294 294 .commit-long {
295 295 overflow-x: auto;
296 296 }
297 297
298 298 .commit-info {
299 299 margin-top: 7px;
300 300 }
301 301
302 302 .tag, .tagtag, .branchtag, .booktag, .metatag, .perm_tag {
303 303 background:transparent;
304 304 border: none;
305 305 box-shadow: none;
306 306 margin-left: 10px;
307 307 font-size: 13px;
308 308 }
309 309
310 310 .tag span, .tag i {
311 311 color: @grey1;
312 312 }
313 313 }
314 314 .commit {
315 315 color: @grey1;
316 316 margin-bottom: 5px;
317 317 white-space: pre;
318 318 }
319 319 .commit.truncate-wrap {
320 320 overflow:hidden;
321 321 text-overflow: ellipsis;
322 322 }
323 323 .commit-author {
324 324 color: @grey1;
325 325 }
326 326 .commit-date {
327 327 color: @grey4;
328 328 }
329 329 }
330 330
331 331 // expand commit message
332 332 #message_expand {
333 333 clear: both;
334 334 display: block;
335 335 color: @rcblue;
336 336 cursor: pointer;
337 337 }
338 338
339 339 #trimmed_message_box {
340 340 max-height: floor(2 * @basefontsize * 1.2); // 2 lines * line-height
341 341 overflow: hidden;
342 342 }
343 343
344 344 // show/hide comments button
345 345 .show-inline-comments {
346 346 display: inline;
347 347 cursor: pointer;
348 348
349 349 .comments-show { display: inline; }
350 350 .comments-hide { display: none; }
351 351
352 352 &.comments-visible {
353 353 .comments-show { display: none; }
354 354 .comments-hide { display: inline; }
355 355 }
356 356 }
357 357
358 358 // Quick Start section
359 359
360 360 .empty-repo {
361 361 border: 1px solid #EAEAEA;
362 362 border-bottom: 0;
363 363 border-radius: @border-radius;
364 364 padding: 0 20px;
365 365 }
366 366
367 367 .empty-repo h3, .quick_start p {
368 368 margin-bottom: 10px;
369 369 }
370 370
371 371 .quick_start pre {
372 372 background: #FCFEFF;
373 373 border: 1px solid #CBDBEB;
374 374 box-shadow: @button-shadow;
375 375 padding: 10px 15px;
376 376 border-radius: 4px;
377 377 color: @grey2;
378 378 }
379 379
380 380 .clear-fix {
381 381 clear: both;
382 382 }
383 383
384 384 .quick_start {
385 385 display: block;
386 386 position: relative;
387 387 border: 1px solid #EAEAEA;
388 388 border-top: 0;
389 389 border-radius: @border-radius;
390 390 padding: 0 20px;
391 391
392 392 // adds some space to make copy and paste easier
393 393 .left-label,
394 394 .right-content {
395 395 line-height: 1.6em;
396 396 }
397 397 }
398 398
399 399
400 400 .submodule {
401 401 .summary-detail {
402 402 width: 100%;
403 403
404 404 .btn-collapse {
405 405 display: none;
406 406 }
407 407 }
408 408 }
409 409
410 410 .codeblock-header {
411 411 float: left;
412 412 display: block;
413 413 width: 100%;
414 414 margin: 0;
415 415
416 416 .stats {
417 417 float: left;
418 418 padding: 10px;
419 419 }
420 420 .stats-filename {
421 421 font-size: 120%;
422 422 }
423 423 .stats-first-item {
424 424 padding: 0px 0px 0px 3px;
425 425 }
426 426
427 427 .stats-info {
428 margin-top: 5px;
429 428 color: @grey4;
430 429 }
431 430
432 431 .buttons {
433 432 float: right;
434 433 text-align: right;
435 434 color: @grey4;
436 435 padding: 10px;
437 margin-top: 15px;
438 436 }
439 437
440 438 .file-container {
441 439 display: inline-block;
442 440 width: 100%;
443 441 }
444 442
445 443 }
446 444
447 445 #summary-menu-stats {
448 446
449 447 .stats-bullet {
450 448 color: @grey3;
451 449 min-width: 3em;
452 450 }
453 451
454 452 .repo-size {
455 453 margin-bottom: .5em;
456 454 }
457 455
458 456 }
459 457
460 458 .rctable.repo_summary {
461 459 border: 1px solid #eaeaea;
462 460 border-radius: 2px;
463 461 border-collapse: inherit;
464 462 border-bottom: 0;
465 463
466 464 th {
467 465 background: @grey7;
468 466 border-bottom: 0;
469 467 }
470 468
471 469 td {
472 470 border-color: #eaeaea;
473 471 }
474 472
475 473 td.td-status {
476 474 padding: 0 0 0 10px;
477 475 }
478 476 }
@@ -1,597 +1,603 b''
1 1 {
2 2 "name": "rcicons",
3 3 "css_prefix_text": "icon-",
4 4 "css_use_suffix": false,
5 5 "hinting": true,
6 6 "units_per_em": 1000,
7 7 "ascent": 850,
8 8 "copyright": "RhodeCode GmbH",
9 9 "glyphs": [
10 10 {
11 11 "uid": "a5f9b6d4d795603e6e29a5b8007cc139",
12 12 "css": "bookmark",
13 13 "code": 59395,
14 14 "src": "custom_icons",
15 15 "selected": true,
16 16 "svg": {
17 17 "path": "M780 990L520 700C510 690 495 690 485 700L225 995C205 1015 180 1000 180 965V35C175 15 190 0 205 0H795C810 0 825 15 825 35V960C825 995 795 1010 780 990Z",
18 18 "width": 1000
19 19 },
20 20 "search": [
21 21 "bookmark"
22 22 ]
23 23 },
24 24 {
25 25 "uid": "fbc028d3a6a0df72f8f508ff5dfbab72",
26 26 "css": "tag",
27 27 "code": 59397,
28 28 "src": "custom_icons",
29 29 "selected": true,
30 30 "svg": {
31 31 "path": "M459.8 62.5L93.8 53.6C75.9 53.6 62.5 67 62.5 84.8L75.9 450.9C75.9 459.8 80.4 464.3 84.8 473.2L549.1 937.5C562.5 950.9 580.4 950.9 593.8 937.5L946.4 584.8C959.8 571.4 959.8 553.6 946.4 540.2L477.7 71.4C473.2 67 464.3 62.5 459.8 62.5ZM357.1 285.7C357.1 321.4 325.9 352.7 290.2 352.7 254.5 352.7 223.2 321.4 223.2 285.7 223.2 250 254.5 218.8 290.2 218.8S357.1 245.5 357.1 285.7Z",
32 32 "width": 1000
33 33 },
34 34 "search": [
35 35 "tag"
36 36 ]
37 37 },
38 38 {
39 39 "uid": "1c67c02366438b324c184ff9e356dca1",
40 40 "css": "branch",
41 41 "code": 59396,
42 42 "src": "custom_icons",
43 43 "selected": true,
44 44 "svg": {
45 45 "path": "M875 250C875 174.1 817 116.1 741.1 116.1S607.1 174.1 607.1 250C607.1 299.1 633.9 339.3 669.6 361.6 651.8 504.5 531.3 544.6 459.8 558V245.5C504.5 223.2 531.3 183 531.3 133.9 531.3 58 473.2 0 397.3 0S263.4 58 263.4 133.9C263.4 183 290.2 227.7 330.4 250V750C290.2 772.3 263.4 817 263.4 866.1 263.4 942 321.4 1000 397.3 1000S531.3 942 531.3 866.1C531.3 817 504.5 772.3 464.3 750V692C526.8 683 629.5 660.7 709.8 580.4 767.9 522.3 799.1 450.9 808 366.1 848.2 343.8 875 299.1 875 250ZM397.3 89.3C424.1 89.3 442 107.1 442 133.9S424.1 178.6 397.3 178.6 352.7 160.7 352.7 133.9 370.5 89.3 397.3 89.3ZM397.3 910.7C370.5 910.7 352.7 892.9 352.7 866.1S370.5 821.4 397.3 821.4 442 839.3 442 866.1 419.6 910.7 397.3 910.7ZM741.1 205.4C767.9 205.4 785.7 223.2 785.7 250S767.9 294.6 741.1 294.6 696.4 276.8 696.4 250 718.8 205.4 741.1 205.4Z",
46 46 "width": 1000
47 47 },
48 48 "search": [
49 49 "branch"
50 50 ]
51 51 },
52 52 {
53 53 "uid": "b75f7b47706aebd803ef370082e8e334",
54 54 "css": "group",
55 55 "code": 59407,
56 56 "src": "custom_icons",
57 57 "selected": true,
58 58 "svg": {
59 59 "path": "M961.5 630.8V646.2C961.5 650 957.7 657.7 950 657.7H788.5 784.6C769.2 638.5 746.2 619.2 707.7 615.4 673.1 607.7 653.8 600 638.5 592.3 646.2 584.6 657.7 580.8 669.2 576.9 715.4 569.2 726.9 553.8 734.6 542.3 742.3 530.8 742.3 519.2 734.6 503.8 726.9 488.5 703.8 461.5 703.8 423.1 703.8 384.6 703.8 319.2 776.9 319.2H784.6 792.3C865.4 323.1 869.2 384.6 865.4 423.1 865.4 461.5 842.3 492.3 834.6 503.8 826.9 519.2 826.9 530.8 834.6 542.3 842.3 553.8 857.7 569.2 900 576.9 953.8 580.8 961.5 623.1 961.5 630.8 961.5 630.8 961.5 630.8 961.5 630.8ZM253.8 646.2C269.2 630.8 292.3 615.4 323.1 611.5 361.5 603.8 384.6 596.2 396.2 584.6 388.5 576.9 376.9 569.2 361.5 565.4 315.4 557.7 303.8 542.3 296.2 530.8 288.5 519.2 288.5 507.7 296.2 492.3 303.8 476.9 326.9 450 326.9 411.5 326.9 373.1 326.9 307.7 253.8 307.7H246.2 234.6C161.5 311.5 157.7 373.1 161.5 411.5 161.5 450 184.6 480.8 192.3 492.3 200 507.7 200 519.2 192.3 530.8 184.6 542.3 169.2 557.7 126.9 565.4 80.8 573.1 73.1 615.4 73.1 619.2 73.1 619.2 73.1 619.2 73.1 619.2V634.6C73.1 638.5 76.9 646.2 84.6 646.2H246.2 253.8ZM707.7 634.6C634.6 623.1 611.5 600 600 580.8 588.5 561.5 588.5 542.3 600 519.2 611.5 496.2 650 450 653.8 388.5 657.7 326.9 653.8 223.1 534.6 219.2H519.2 503.8C384.6 223.1 380.8 323.1 384.6 384.6 388.5 446.2 423.1 492.3 438.5 515.4 450 538.5 450 557.7 438.5 576.9 426.9 596.2 403.8 619.2 330.8 630.8 257.7 642.3 246.2 711.5 246.2 719.2 246.2 719.2 246.2 719.2 246.2 719.2V742.3C246.2 750 253.8 757.7 261.5 757.7H519.2 776.9C784.6 757.7 792.3 750 792.3 742.3V719.2C792.3 719.2 792.3 719.2 792.3 719.2 788.5 715.4 780.8 646.2 707.7 634.6Z",
60 60 "width": 1000
61 61 },
62 62 "search": [
63 63 "group"
64 64 ]
65 65 },
66 66 {
67 67 "uid": "7ae0ef039bb0217d9581e44b09448905",
68 68 "css": "fork",
69 69 "code": 59409,
70 70 "src": "custom_icons",
71 71 "selected": true,
72 72 "svg": {
73 73 "path": "M792.3 196.2C792.3 138.5 746.2 96.2 692.3 96.2 634.6 96.2 592.3 142.3 592.3 196.2 592.3 230.8 611.5 261.5 638.5 280.8 626.9 365.4 569.2 403.8 511.5 423.1 453.8 407.7 396.2 369.2 384.6 280.8 411.5 261.5 430.8 230.8 430.8 196.2 430.8 138.5 384.6 96.2 330.8 96.2S223.1 138.5 223.1 196.2C223.1 234.6 246.2 269.2 276.9 284.6 288.5 392.3 353.8 473.1 457.7 511.5V673.1C426.9 692.3 407.7 723.1 407.7 761.5 407.7 819.2 453.8 861.5 507.7 861.5S607.7 815.4 607.7 761.5C607.7 723.1 588.5 692.3 557.7 673.1V511.5C661.5 473.1 726.9 392.3 738.5 284.6 769.2 265.4 792.3 234.6 792.3 196.2ZM326.9 161.5C346.2 161.5 361.5 176.9 361.5 196.2S346.2 226.9 326.9 226.9 292.3 215.4 292.3 196.2 307.7 161.5 326.9 161.5ZM507.7 796.2C488.5 796.2 473.1 780.8 473.1 761.5S488.5 726.9 507.7 726.9C526.9 726.9 542.3 742.3 542.3 761.5S526.9 796.2 507.7 796.2ZM692.3 161.5C711.5 161.5 726.9 176.9 726.9 196.2S711.5 226.9 692.3 226.9 657.7 211.5 657.7 192.3 673.1 161.5 692.3 161.5Z",
74 74 "width": 1000
75 75 },
76 76 "search": [
77 77 "fork"
78 78 ]
79 79 },
80 80 {
81 81 "uid": "65e66c3e7d74e2c345fb78fadd400d3f",
82 82 "css": "rhodecode",
83 83 "code": 59441,
84 84 "src": "custom_icons",
85 85 "selected": true,
86 86 "svg": {
87 87 "path": "M174.6 216.8C173.4 220.9 172.2 225 171 229.1 168.1 239.1 165.2 249.1 162.3 259.1 158.7 271.6 155 284.2 151.4 296.7 148 308.4 144.6 320.1 141.2 331.8 139 339.3 136.8 346.8 134.7 354.3 134.4 355.4 134.1 356.5 133.7 357.6 133.7 357.7 133.9 358.2 134 358.3 134.3 359 134.5 359.7 134.8 360.5 137.2 367.3 139.7 374.1 142.1 381 146 392 149.9 403 153.9 414.1 158.3 426.5 162.8 439 167.2 451.4 171.1 462.5 175.1 473.6 179 484.7 181.5 491.7 184 498.6 186.4 505.6 186.8 506.7 187.2 507.7 187.5 508.8 187.8 509.6 188.6 510.4 189 511.1 192.8 516.9 196.5 522.6 200.3 528.4 206.5 537.9 212.7 547.4 219 556.9 226.2 567.9 233.4 578.9 240.6 590 247.3 600.3 254.1 610.6 260.8 620.9 265.6 628.2 270.4 635.6 275.2 642.9 276.4 644.8 277.6 646.6 278.9 648.5 279.2 649 279.5 649.5 279.8 649.8 282.7 652.6 285.5 655.4 288.4 658.2 294.6 664.3 300.9 670.5 307.1 676.6 315.5 684.9 323.9 693.2 332.4 701.4 341.8 710.6 351.2 719.9 360.6 729.1 369.8 738.1 378.9 747.1 388.1 756.1 395.8 763.7 403.6 771.3 411.3 778.9 416.4 783.9 421.5 788.9 426.6 793.9 428.2 795.5 429.8 797.3 431.6 798.6 438.9 803.9 446.1 809.2 453.4 814.5 463.7 822 473.9 829.5 484.2 837 487.6 839.5 491.1 842 494.5 844.5 495.3 845.1 496.1 845.7 496.9 846.3 497.2 846.5 497.2 846.6 497.6 846.4 504.7 842.7 511.8 839.1 518.9 835.4 530.3 829.5 541.7 823.6 553.1 817.7 559.2 814.5 565.4 811.4 571.5 808.2 571.9 808 572.3 807.1 572.6 806.8 573.7 805.4 574.8 804 576 802.5 580.2 797.2 584.3 791.9 588.5 786.7 594.7 778.9 600.8 771.1 607 763.3 614.5 753.8 622 744.3 629.5 734.8 637.7 724.5 645.8 714.1 654 703.8 662.1 693.5 670.3 683.2 678.4 672.9 685.9 663.5 693.3 654 700.8 644.6 706.9 636.9 713 629.2 719.1 621.5 723.2 616.4 727.2 611.2 731.3 606.1 732.7 604.4 734 602.6 735.4 600.9 735.2 600.8 734.8 600.8 734.6 600.7 733.8 600.5 733 600.4 732.2 600.2 729.1 599.6 726 598.9 722.9 598.2 718 597.1 713 596 708.1 594.8 701.5 593.2 694.9 591.5 688.3 589.7 680.2 587.5 672.2 585.2 664.1 582.9 654.7 580.1 645.4 577.2 636.1 574.1 625.6 570.6 615.2 567 604.8 563.3 593.4 559.1 582 554.8 570.8 550.2 558.6 545.3 546.6 540.1 534.6 534.8 521.9 529.1 509.3 523.1 496.8 516.8 483.7 510.2 470.7 503.4 457.9 496.2 444.6 488.7 431.4 480.9 418.5 472.8 405.1 464.4 392 455.6 379.1 446.4 365.9 437 352.9 427.1 340.3 416.9 327.4 406.4 314.8 395.5 302.7 384.2 290.3 372.6 278.3 360.6 266.8 348.1 255.1 335.3 243.8 322.1 233.2 308.4 222.3 294.4 212 279.9 202.4 265 192.5 249.7 183.4 233.9 175 217.8 175 217.4 174.8 217.1 174.6 216.8ZM172.1 214.2C170.7 218.7 169.3 223.3 167.8 227.8 164.5 238.5 161.1 249.2 157.8 259.9 153.9 272.4 150 285 146.1 297.5 143 307.5 139.9 317.4 136.7 327.4 135.9 330.1 135 332.7 134.2 335.4 134 336.1 133.6 336.7 133.8 337.4 135.4 342.2 137 347.1 138.6 351.9 141.9 361.9 145.2 371.8 148.6 381.8 152.7 394.1 156.8 406.5 160.9 418.8 164.9 430.8 168.9 442.8 172.9 454.8 175.9 463.7 178.8 472.6 181.8 481.4 182.6 483.8 183.4 486.2 184.2 488.7 184.4 489.4 184.6 490.1 184.9 490.8 187.2 495 189.5 499.2 191.8 503.4 196.8 512.6 201.9 521.8 206.9 531 213.2 542.4 219.4 553.9 225.7 565.3 231.7 576.2 237.6 587.1 243.6 598 247.8 605.6 251.9 613.2 256.1 620.8 257.3 623 258.2 625.4 259.9 627.2 264.1 631.7 268.3 636.2 272.5 640.7 280.2 648.9 287.9 657.2 295.5 665.4 304.5 675 313.5 684.7 322.4 694.3 330.5 703 338.6 711.7 346.7 720.4 351.8 725.8 356.8 731.3 361.9 736.7 363.5 738.4 365 740 366.6 741.6 372.3 747.3 378 753 383.7 758.7 392.5 767.5 401.2 776.2 410 785 419.1 794.1 428.3 803.3 437.4 812.4 444.2 819.2 451.1 826.1 457.9 832.9 459.6 834.6 461.3 836.3 463 838 463.3 838.3 463.6 838.6 463.8 838.8 463.9 838.9 465.1 838.7 465.3 838.6 475.9 837.2 486.5 835.8 497 834.5 505.6 833.4 514.1 832.3 522.7 831.2 523 831.2 523.7 830.1 523.9 829.9 525.1 828.6 526.3 827.2 527.6 825.9 532.1 820.9 536.7 815.9 541.2 810.9 547.9 803.5 554.6 796.1 561.4 788.7 569.6 779.7 577.7 770.7 585.9 761.8 594.8 752 603.6 742.3 612.5 732.5 621.3 722.8 630.1 713.1 639 703.4 647 694.5 655.1 685.7 663.1 676.8 669.6 669.6 676.2 662.4 682.7 655.2 687 650.5 691.3 645.8 695.6 641 696.6 639.9 697.7 638.7 698.7 637.6 698.9 637.4 699.6 636.9 699.6 636.6 699.6 636.5 696.6 635.7 696.5 635.7 693.5 634.8 690.4 633.9 687.4 633 682.6 631.5 677.8 630 673 628.4 666.6 626.3 660.1 624.1 653.8 621.8 645.9 619 638.1 616.1 630.3 613.1 621.2 609.6 612.1 606 603.1 602.2 592.9 598 582.8 593.6 572.8 589 561.8 584 550.8 578.8 540 573.4 528.3 567.6 516.7 561.6 505.2 555.3 493 548.7 480.9 541.8 469 534.6 456.5 527.1 444.1 519.3 431.9 511.2 419.2 502.8 406.7 494 394.5 484.9 381.8 475.5 369.5 465.8 357.4 455.7 345 445.3 332.8 434.6 321.1 423.4 309.1 412 297.4 400.2 286.2 388 274.7 375.5 263.7 362.6 253.2 349.3 242.5 335.7 232.3 321.7 222.8 307.2 213 292.4 203.9 277.2 195.5 261.7 186.8 246.5 179 230.5 172.1 214.2ZM169.5 204C168.8 207.8 168.1 211.6 167.3 215.4 165.5 224.9 163.7 234.5 161.9 244 159.5 256.5 157.1 269 154.7 281.5 152.3 294.2 149.8 307 147.4 319.7 145.5 329.9 143.5 340.1 141.6 350.3 140.7 355.2 139.7 360.1 138.8 365 138.7 365.7 139.1 366.4 139.3 367 140.2 369.6 141.1 372.2 142 374.8 145.4 384.5 148.7 394.3 152.1 404 156.4 416.4 160.7 428.7 165 441.1 168.8 452.1 172.6 463 176.4 474 178.3 479.5 180.2 485 182.1 490.5 182.3 491.2 182.7 491.8 183 492.4 184.2 494.8 185.4 497.1 186.5 499.5 190.9 508.4 195.4 517.2 199.8 526.1 205.6 537.7 211.4 549.3 217.2 560.9 222.7 571.9 228.2 583 233.8 594 237.4 601.2 241 608.3 244.6 615.5 245.2 616.6 245.7 617.7 246.3 618.8 246.7 619.6 247.6 620.4 248.2 621.1 252.8 626.6 257.4 632.1 262 637.7 269.5 646.7 276.9 655.6 284.4 664.6 292.8 674.7 301.3 684.9 309.7 695 317.2 704 324.8 713.1 332.3 722.1 337 727.8 341.8 733.5 346.5 739.1 347.2 740 347.9 740.8 348.7 741.7 348.9 741.9 349.2 742 349.4 742.2 350.2 742.7 350.9 743.2 351.7 743.7 358.7 748.5 365.8 753.3 372.8 758.1 383.3 765.3 393.9 772.5 404.4 779.7 414.6 786.6 424.7 793.6 434.9 800.5 440.8 804.5 446.7 808.6 452.7 812.6 456.3 815.1 459.5 818.1 462.9 820.8 472.5 828.7 482.1 836.7 491.7 844.6 498.5 850.2 505.4 855.9 512.2 861.5 512.8 862 512.7 861.9 513.3 861.3 514.2 860.3 515.2 859.2 516.1 858.2 520 853.9 524 849.6 527.9 845.3 534 838.6 540.2 831.9 546.3 825.2 554 816.8 561.7 808.3 569.4 799.9 578.1 790.4 586.7 781 595.4 771.5 604.4 761.7 613.3 751.9 622.3 742.1 630.9 732.6 639.6 723.2 648.2 713.7 655.9 705.3 663.6 696.9 671.3 688.5 677.4 681.8 683.5 675.1 689.6 668.4 693.5 664.1 697.4 659.9 701.3 655.6 702.4 654.4 703.5 653.2 704.6 652 704.6 652 704.6 652 704.6 652 704.6 652 704.6 652 704.6 652 704.6 652.1 701.6 651.3 701.5 651.3 698.5 650.5 695.5 649.5 692.6 648.6 687.9 647.1 683.1 645.5 678.4 643.8 672.1 641.6 665.8 639.2 659.5 636.9 651.8 634 644.1 630.9 636.4 627.8 627.5 624.1 618.6 620.3 609.7 616.4 599.7 612 589.8 607.4 580 602.7 569.2 597.5 558.4 592.1 547.7 586.6 536.2 580.6 524.8 574.4 513.4 568 501.4 561.2 489.5 554.2 477.7 546.9 465.3 539.3 453.1 531.4 441.1 523.3 428.6 514.8 416.3 506.1 404.2 497 391.7 487.7 379.5 478 367.5 468 355.2 457.8 343.2 447.2 331.5 436.3 319.6 425.2 308 413.6 296.8 401.7 285.4 389.6 274.5 377.1 264 364.3 253.3 351.2 243.2 337.8 233.6 323.9 223.8 309.8 214.6 295.4 206.1 280.5 197.4 265.4 189.4 249.9 182.1 234 177.7 224.2 173.5 214.2 169.5 204ZM866 183.5C863.9 179.4 861.1 176.2 857.1 174 851.9 171.1 846.2 168.9 840.7 166.5 829.5 161.7 818.2 157.4 806.7 153.4 783.6 145.4 760 138.9 736.3 132.9 711.7 126.7 687.1 120.9 662.3 115.7 637.1 110.4 611.7 105.6 586.3 101.4 561.2 97.2 536 93.1 510.5 91.1 497.8 90.1 485 89.9 472.4 91.3 465.9 92 459.4 93.2 453 94.2 446.6 95.2 440.1 96.2 433.7 97.3 408.2 101.5 382.8 106 357.4 111 332.2 115.9 307.1 121.2 282.1 126.9 257.2 132.5 232.6 139.2 208.4 147.3 196.3 151.4 184.2 155.8 172.3 160.5 166.4 162.8 160.5 165.2 154.6 167.7 151.7 168.9 148.8 170.2 145.8 171.4 143.2 172.5 140.6 173.5 138.1 174.7 134 176.7 130.6 179.7 128.3 183.6 127 185.8 126.2 188.2 125.3 190.6 124.2 193.6 123.1 196.6 122.1 199.6 118.1 211.5 114.9 223.7 112.5 236 107.7 260.4 106 285.4 106.8 310.2 107.2 322.7 108.2 335.3 109.7 347.7 111.2 360.2 112.7 372.8 115.1 385.2 119.8 410.4 126.7 435.1 134.8 459.3 138.9 471.4 143.3 483.5 147.9 495.4 152.2 506.5 157.5 517.3 162.7 528 173 549.2 184.4 569.8 196.6 589.9 208.8 609.9 221.9 629.3 235.7 648.1 249.5 666.8 264.1 685 279.3 702.6 295.3 721.1 311.7 739.2 328.6 756.9 345.6 774.8 363 792.2 381 809 398.9 825.9 417.4 842.2 436.4 857.8 445.6 865.4 454.9 872.8 464.2 880.2 473.6 887.7 483.1 895.1 492 903.2 494.3 905.2 496.5 907.3 498.7 909.5 498.9 909.7 499.7 910.8 500 910.8 500.2 910.8 500.5 910.8 500.7 910.8 501.2 910.8 502 911 502.5 910.8 507.3 907.1 512 903.3 516.8 899.6 526.2 892.1 535.6 884.6 544.9 876.9 563.3 861.7 581.4 846.2 599.2 830.3 616.9 814.5 634.1 798.2 651 781.5 667.9 764.7 684.4 747.5 700.3 729.7 716.3 711.8 731.8 693.4 746.5 674.4 761 655.7 774.8 636.5 787.8 616.8 800.7 597.2 812.8 577 823.8 556.2 835 535.1 845.2 513.5 854.3 491.4 863.4 469.1 871.2 446.3 877.3 423 883.4 399.9 887.8 376.4 890.3 352.7 892.9 328.6 893.4 304.3 892 280 891.8 276.9 891 273.8 890.3 270.7 889.7 267.7 889 264.6 888.4 261.6 887.2 255.7 886 249.9 884.7 244 882.3 233 879.7 222 876.5 211.1 873.4 201.8 870.1 192.5 866 183.5 863.5 178.4 878.8 211.7 866 183.5ZM814.8 393.5C808.1 418.2 799.5 442.5 789.4 466 780 487.9 770 509.6 758.5 530.5 747.4 550.7 735.1 570.3 722 589.3 708.8 608.4 694.7 626.8 680 644.8 664.8 663.4 649 681.5 632.7 699.1 615.9 717.3 598.5 734.9 580.5 752 562.5 769.1 544.1 785.7 525.1 801.6 515.7 809.5 506.1 817.3 496.5 824.9 496.1 825.2 495.2 826.3 494.7 826.3 494 826.3 493.3 826.3 492.6 826.3 492 826.3 491.4 825.5 491 825.1 490.5 824.6 490 824.1 489.5 823.6 488.4 822.6 487.2 821.5 486.1 820.5 481.6 816.6 476.9 813.1 472.2 809.4 469.9 807.6 467.6 805.7 465.3 803.8 463.1 801.9 461 799.8 458.8 797.8 454.2 793.7 449.7 789.6 445.2 785.5 435.9 777 426.6 768.5 417.5 759.8 408.4 751.1 399.5 742.3 390.9 733.2 386.7 728.8 382.7 724.3 378.4 720 374.2 715.8 370 711.5 365.8 707.2 349.1 690 332.9 672.5 317.4 654.3 301.8 636 286.9 617 273.1 597.3 259.2 577.5 246.4 556.9 234.5 535.8 222.8 515 212.1 493.7 202.6 471.8 193.1 449.9 184.8 427.4 177.9 404.6 176.1 398.6 174.4 392.6 173.1 386.5 171.7 380.1 170.6 373.6 169.6 367.1 167.6 354.2 166.3 341.2 165.5 328.2 164.7 315.3 164.3 302.3 164.5 289.3 164.7 276.7 165.9 264.2 167.5 251.7 167.9 248.5 168.3 245.4 168.7 242.2 168.9 240.6 169.1 239.1 169.3 237.5 169.5 235.9 169.6 234.3 169.8 232.7 170.1 230.3 171.1 228.1 171.7 225.7 172 224.5 172.2 223.2 172.2 221.9 172.2 220.8 172.8 220.1 173.6 219.5 174.6 218.8 175.6 218.3 176.5 217.5 177.1 217 177.6 216.6 178.4 216.3 179.2 216 180.1 215.7 180.9 215.3 183.9 214.2 186.8 213 189.8 211.9 195.7 209.7 201.6 207.5 207.6 205.3 231.3 196.7 255.3 189 279.7 182.4 292 179.1 304.3 176.1 316.7 173.5 322.9 172.2 329.1 170.6 335.4 169.3 341.7 167.9 348 166.6 354.3 165.4 379.8 160.4 405.4 156.3 431.1 152.5 444 150.6 457 148.8 470 147 473.2 146.6 476.5 146.1 479.7 145.7 481.3 145.5 482.8 145.3 484.4 145.1 485.7 144.9 487.1 145 488.4 145.1 493.9 145.1 499.5 145.3 504.9 146.3 506.2 146.5 507.4 146.8 508.6 147.1 510.1 147.5 511.5 147.8 513 148 516.1 148.4 519.2 148.9 522.3 149.3 528.6 150.2 534.8 151.1 541.1 152 553.7 153.8 566.4 155.7 579 157.7 604.4 161.7 629.7 166 654.8 171.4 680 176.8 705 183.2 729.7 190.3 742.1 193.9 754.4 197.7 766.6 201.7 772.7 203.7 778.7 205.8 784.7 207.9 787.7 209 790.7 210 793.7 211.1 795.1 211.6 796.6 212.1 798 212.7 798.7 213 799.4 213.2 800.1 213.5 800.8 213.8 801.9 214 802.4 214.5 803.6 215.7 805.3 216.5 806.3 217.9 806.8 218.7 807.1 219.5 807.2 220.5 807.3 221.2 807.2 221.8 807.4 222.5 807.7 223.4 807.9 224.3 808.1 225.2 809.8 231.5 811.2 237.9 812.3 244.4 813.4 250.8 814.1 257.2 814.5 263.6 814.7 266.8 814.8 270 814.9 273.2 814.9 274 814.9 274.7 814.9 275.5 814.9 276.3 815.2 277.1 815.3 277.8 815.7 279.5 816 281.1 816.4 282.8 821.3 306.5 822.7 330.7 820.7 354.8 819.6 367.7 817.6 380.7 814.8 393.5 807.1 421.7 822.5 357.6 814.8 393.5ZM617.6 393.5C616.1 389 614.6 384.5 613.1 379.9 612.9 379.3 612.7 378.7 612.5 378.1 612.4 377.7 612.5 377.1 612.4 376.7 612.3 376.1 612.2 375.5 612.1 374.9 611.8 373.8 611.4 372.8 610.8 371.9 609.7 370.1 608.1 368.5 606.5 367 604.7 365.2 602.4 362.7 599.6 362.7 601.6 360.7 604.3 360 606.5 358.3 607.6 357.4 608.5 356.5 609.7 355.7 610.5 355.2 611.6 354.7 612.1 353.8 612.3 353.4 612.4 352.9 612.4 352.5 612.9 352 613.3 351.5 613.7 350.9 614.4 349.8 614.7 348.6 614.9 347.3 615.1 345.1 615 342.9 615 340.7 615 338.4 615 336.1 615 333.8 615 331.4 615 329 614.4 326.6 613.1 321.5 610 316.8 606.4 313.1 604.7 311.4 603 309.9 601 308.6 598.3 306.9 595.5 305.5 592.7 304.1 589.9 302.7 586.9 301.8 583.8 301.4 581.4 301.1 579 301.1 576.6 301.1 573.9 301.1 571.2 301.1 568.5 301.1 556.2 301.1 543.8 301.1 531.5 301.1 526.9 301.1 522.3 301.1 517.7 301.1 516.9 301.1 516.1 301.1 515.2 301.1 515.1 301.1 515.2 305.3 515.2 305.6 515.2 308.8 515.2 311.9 515.2 315.1 515.2 316.2 515.2 317.3 515.2 318.4 515.2 318.9 515 319.1 515.5 319.1 516.7 319.1 528 319 528 319.2 528 327.2 528 335.2 528 343.2 528 355.8 528 368.3 528 380.9 528 384.6 528 388.3 528 392 528 392.2 528.1 393.4 527.9 393.4 525.4 393.4 522.8 393.4 520.3 393.4 518.9 393.4 517.6 393.4 516.2 393.4 515.9 393.4 515.2 393.2 515.2 393.6 515.2 395.7 515.2 397.8 515.2 400 515.2 401 515.2 414 515.2 414 524.7 414 534.3 414 543.8 414 549.3 414 554.8 414 560.2 414 561.4 414 562.5 414 563.7 414 564 414 563.8 411.1 563.8 410.7 563.8 405.1 563.8 399.6 563.8 394 563.8 393.4 563.9 393.5 563.3 393.5 562 393.5 560.7 393.5 559.3 393.5 557.8 393.5 556.3 393.5 554.8 393.5 554.6 393.5 553.5 393.7 553.5 393.4 553.5 388.4 553.5 383.4 553.5 378.4 553.5 375.6 553.5 372.9 553.5 370.1 553.5 369.4 553.5 368.8 553.5 368.1 553.5 367.7 554.2 367.9 554.5 367.9 557.4 367.9 560.2 367.9 563.1 367.9 565 367.9 566.9 367.9 568.8 367.9 570.1 367.9 571.6 367.7 572.8 368.1 573.9 368.4 574.8 369 575.7 369.7 576.8 370.6 578.3 371.8 578.9 373.1 579.2 373.8 579.2 374.5 579.2 375.3 579.2 376.6 579.6 377.7 580.2 378.9 580.7 380 581.3 381 581.6 382.2 581.7 382.6 581.7 383 581.8 383.4 581.9 384 582 384.6 582.1 385.1 583.1 390.9 584.2 396.6 585.2 402.4 585.6 404.9 586.1 407.3 586.5 409.8 586.6 410.3 586.7 410.8 586.8 411.3 586.8 411.4 587.2 411.4 587.4 411.4 597.8 411.4 608.3 411.4 618.7 411.4 619.2 411.4 619.6 411.4 620.1 411.4 620.2 411.4 620.2 410.7 620.2 410.6 620.2 408.2 620.2 405.7 620.2 403.3 620.2 398.3 620.2 393.3 620.2 388.4 620.2 388.4 620.2 388.4 620.2 388.4 619.3 390.1 618.5 391.8 617.6 393.5ZM592 339.7C592 342 589.2 342.8 587.7 344.1 587.4 344.3 587.1 344.6 586.9 344.8 586.7 344.8 586.4 344.8 586.2 344.9 585.8 345 585.4 345.2 585.1 345.4 584.4 345.9 583.9 346.6 583.2 347 582.1 347.5 580.7 347.3 579.6 347.3 577.9 347.3 576.3 347.3 574.6 347.3 573.9 347.3 573.2 347.3 572.5 347.3 569.5 347.3 566.4 347.3 563.4 347.3 563 347.3 558.8 347.4 558.8 347.2 558.8 337.9 558.8 328.5 558.8 319.2 558.8 319.1 571.7 319.2 573 319.2 577 319.2 581 319.1 584.9 320.1 586.4 320.5 587.8 321 589.2 321.6 590.1 322.1 591 323.2 591.6 324 593.1 325.7 594.1 327.8 594.5 330 594.6 330.7 594.6 331.3 594.6 332 594.3 332.6 594 333.2 593.7 333.9 593.3 334.7 592.9 335.5 592.6 336.3 592.1 337.4 592 338.5 592 339.7ZM722.6 393.5C722.6 384.2 722.6 374.9 722.6 365.6 722.6 357.1 720.9 348 714.6 341.9 707.5 335.1 696.4 333.9 687 334.7 685.1 334.9 683.2 335.3 681.4 336.1 680.4 336.5 679.5 336.9 678.6 337.6 678 338.1 677.3 338.5 676.7 338.8 673.6 340.4 670.5 341.6 668.8 344.9 668.8 335.9 668.8 326.8 668.8 317.8 668.8 311.9 668.8 306 668.8 300.1 668.8 298.4 668.8 296.6 668.8 294.9 668.8 294.4 669.1 293.7 668.5 293.7 657.9 293.7 647.3 293.7 636.7 293.7 635.5 293.7 634.2 293.7 633 293.7 633 293.7 633 297.8 633 298.1 633 303.4 633 308.7 633 314 633 314.3 633.8 314.2 634 314.2 635.4 314.2 636.7 314.2 638.1 314.2 640.6 314.2 643.2 314.2 645.7 314.2 645.9 314.2 645.8 319.4 645.8 319.8 645.8 331.2 645.8 342.6 645.8 353.9 645.8 364.9 645.8 375.8 645.8 386.8 645.8 388 645.8 389.2 645.8 390.3 645.8 391.2 645.7 391 644.6 391 641.6 391 638.7 391 635.7 391 634.8 391 633.9 391 633 391 632.9 391 632.9 391.9 632.9 392 632.9 397.7 632.9 403.4 632.9 409 632.9 409.8 632.9 410.5 632.9 411.3 632.9 411.5 633 411.5 633.2 411.5 634.5 411.5 635.9 411.5 637.2 411.5 649.1 411.5 661 411.5 672.9 411.5 673.4 411.5 681.5 411.5 681.5 411.5 681.5 406.5 681.5 401.5 681.5 396.5 681.5 394.7 681.5 392.9 681.5 391.1 681.5 391.1 675.6 391.1 675.2 391.1 674.8 391.1 668.7 391.1 668.7 391.1 668.7 389.8 668.7 388.5 668.7 387.3 668.7 381.2 668.7 375 668.7 368.9 668.7 366.5 668.7 364.2 668.7 361.8 668.7 361.3 668.7 360.9 668.7 360.4 668.7 360 670.3 358.8 670.6 358.5 671.7 357.5 672.8 356.5 674.2 355.8 674.7 355.5 675.3 355.3 675.8 355.3 676.5 355.2 676.8 354.8 677.4 354.3 678.5 353.5 679.7 353 681 352.8 683.6 352.4 685.8 352.7 687.9 354.2 689.1 355.1 690.1 356.1 691.2 357.2 692 358 692.7 358.8 693.3 359.8 694.2 361.6 694.3 363.7 694.3 365.7 694.4 369.3 694.3 372.9 694.3 376.6 694.3 387.8 694.3 399 694.3 410.3 694.3 410.9 694 411.6 694.7 411.6 696.4 411.6 698.1 411.6 699.8 411.6 706 411.6 712.3 411.6 718.5 411.6 722.4 411.6 726.3 411.6 730.2 411.6 730.2 411.6 730.2 398.5 730.2 397.5 730.2 395.4 730.2 393.3 730.2 391.2 727.8 391.8 725.2 392.6 722.6 393.5ZM730.3 270.6C727.9 270.6 725.4 270.6 723 270.6 722 270.6 721.1 270.6 720.1 270.6 720 270.6 719.6 271.3 719.6 271.4 716.5 276 713.4 280.6 710.4 285.3 708.9 287.5 707.4 289.7 706 292 705.6 292.5 705.3 293.1 704.9 293.6 704.6 294.1 704.8 294.9 704.8 295.4 704.8 295.6 704.8 298.8 704.8 298.8 705.4 298.8 706 298.8 706.5 298.8 709.5 298.8 712.4 298.8 715.4 298.8 717.8 298.8 720.1 298.8 722.5 298.8 723 298.8 722.7 299.6 722.7 299.9 722.7 301.4 722.7 302.9 722.7 304.4 722.7 305.8 722.7 307.1 722.7 308.5 722.7 309.3 723 309.1 723.8 309.1 725.3 309.1 726.9 309.1 728.4 309.1 728.7 309.1 730.3 309.3 730.3 308.9 730.3 306.2 730.3 303.4 730.3 300.7 730.3 300.4 730.1 298.8 730.5 298.8 731.9 298.8 733.3 298.8 734.6 298.8 734.7 298.8 735.4 298.8 735.4 298.8 735.4 298.2 735.4 297.7 735.4 297.1 735.4 296.9 735.4 293.7 735.4 293.7 734.1 293.7 732.9 293.7 731.6 293.7 731.1 293.7 730.3 294 730.3 293.4 730.3 285.7 730.3 278.1 730.3 270.6ZM722.6 285.9C722.6 287.2 722.6 288.5 722.6 289.7 722.6 290.6 722.6 291.4 722.6 292.3 722.6 292.5 722.7 293.4 722.6 293.6 722.5 293.7 721.6 293.6 721.5 293.6 720.6 293.6 719.7 293.6 718.8 293.6 717.5 293.6 716.2 293.6 715 293.6 716.3 291.6 717.7 289.6 719 287.6 719.6 286.7 720.2 285.9 720.8 285.1 722.4 283.1 722.6 280.7 722.6 278.2 722.6 280.8 722.6 283.4 722.6 285.9ZM763.6 288.5C760.9 285.8 756.2 285.9 752.6 285.9 752 285.9 751.4 285.9 750.8 285.9 750.8 285.9 750.8 284.8 750.8 284.7 750.8 283.4 750.8 282.1 750.8 280.8 750.8 280.7 763.9 280.8 765.2 280.8 765.7 280.8 766.2 281 766.2 280.5 766.2 279.1 766.2 277.7 766.2 276.4 766.2 275.3 766.2 274.2 766.2 273.2 766.2 273.2 764.9 273.2 764.9 273.2 759.2 273.2 753.5 273.2 747.8 273.2 747.2 273.2 746.5 273.2 745.9 273.2 745.7 273.2 745.7 273.6 745.7 273.8 745.4 276 745.1 278.2 744.9 280.4 744.3 284.8 743.8 289.3 743.2 293.7 747 293.7 751.5 293.1 755.1 294.8 757.9 296.2 759 299.4 758.5 302.4 758 305.8 754.4 306.5 751.5 306.5 749.6 306.5 743.2 307 743.2 303.9 742.3 306.5 741.5 309 740.6 311.6 742.3 311.6 744 312.6 745.6 313.2 748 314.1 750.5 314.3 753 314.1 756.9 313.8 761 312.5 763.6 309.4 766.3 306.1 766.2 301.9 766.2 297.8 766.2 295.6 766.2 293.3 765.7 291.1 765.5 290.1 765 288.6 763.7 288.5 763.7 288.5 763.6 288.5 763.6 288.5 761 285.9 766.2 288.5 763.6 288.5Z",
88 88 "width": 1000
89 89 },
90 90 "search": [
91 91 "rhodecode"
92 92 ]
93 93 },
94 94 {
95 95 "uid": "e5ad8728e6d6290aff4b6ffcfcaa9167",
96 96 "css": "up",
97 97 "code": 59442,
98 98 "src": "custom_icons",
99 99 "selected": true,
100 100 "svg": {
101 101 "path": "M686.5 595.8L513.6 379.1C506.3 369.9 492.4 369.9 485.1 379.1L312.2 595.8C302.7 607.8 311.2 625.4 326.5 625.4H672.2C687.5 625.4 696 607.8 686.5 595.8Z",
102 102 "width": 1000
103 103 },
104 104 "search": [
105 105 "up"
106 106 ]
107 107 },
108 108 {
109 109 "uid": "6e459e39444c93a2c017f258186765d6",
110 110 "css": "unlock",
111 111 "code": 59399,
112 112 "src": "custom_icons",
113 113 "selected": true,
114 114 "svg": {
115 115 "path": "M780.8 434.6H396.2V342.3C396.2 284.6 438.5 238.5 492.3 226.9 492.3 226.9 492.3 226.9 496.2 226.9 503.8 226.9 507.7 226.9 515.4 226.9 515.4 226.9 519.2 226.9 519.2 226.9 519.2 226.9 519.2 226.9 523.1 226.9 530.8 226.9 538.5 226.9 546.2 230.8 546.2 230.8 546.2 230.8 546.2 230.8 553.8 230.8 557.7 234.6 565.4 238.5 565.4 238.5 569.2 238.5 569.2 242.3 573.1 246.2 580.8 246.2 584.6 250 584.6 250 584.6 250 584.6 250 588.5 253.8 596.2 257.7 600 261.5 600 261.5 603.8 265.4 603.8 265.4 607.7 269.2 611.5 273.1 615.4 276.9 615.4 276.9 615.4 276.9 619.2 280.8 623.1 284.6 626.9 292.3 630.8 300 630.8 300 630.8 303.8 630.8 303.8 634.6 307.7 634.6 315.4 634.6 319.2 634.6 319.2 634.6 323.1 634.6 323.1 634.6 323.1 634.6 323.1 634.6 326.9 638.5 338.5 646.2 346.2 657.7 346.2H715.4C730.8 346.2 742.3 334.6 738.5 319.2 738.5 319.2 738.5 319.2 738.5 319.2 738.5 319.2 738.5 315.4 738.5 315.4 738.5 307.7 734.6 303.8 734.6 296.2 734.6 292.3 734.6 292.3 730.8 288.5 730.8 273.1 730.8 269.2 726.9 261.5 726.9 261.5 726.9 257.7 723.1 257.7 719.2 250 715.4 242.3 711.5 234.6 711.5 234.6 707.7 230.8 707.7 230.8 703.8 223.1 700 219.2 696.2 215.4 696.2 211.5 692.3 211.5 692.3 207.7 688.5 203.8 684.6 196.2 680.8 192.3 680.8 192.3 676.9 188.5 676.9 188.5 669.2 180.8 665.4 176.9 657.7 169.2 657.7 169.2 653.8 169.2 653.8 165.4 650 161.5 642.3 157.7 634.6 153.8 630.8 153.8 630.8 150 626.9 150 623.1 146.2 615.4 142.3 611.5 142.3 607.7 142.3 607.7 138.5 603.8 138.5 596.2 134.6 588.5 130.8 580.8 130.8 580.8 130.8 580.8 130.8 580.8 130.8 573.1 126.9 565.4 126.9 553.8 123.1 550 123.1 550 123.1 546.2 123.1 538.5 123.1 534.6 123.1 526.9 119.2 523.1 119.2 519.2 119.2 519.2 119.2 511.5 119.2 503.8 119.2 496.2 119.2 496.2 119.2 492.3 119.2 492.3 119.2 484.6 119.2 476.9 123.1 465.4 123.1 461.5 123.1 453.8 126.9 450 126.9 450 126.9 446.2 126.9 446.2 126.9 353.8 153.8 288.5 242.3 288.5 342.3V434.6H246.2C230.8 434.6 223.1 446.2 223.1 457.7V857.7C223.1 873.1 234.6 880.8 246.2 880.8H780.8C796.2 880.8 803.8 869.2 803.8 857.7V457.7C807.7 446.2 796.2 434.6 780.8 434.6Z",
116 116 "width": 1000
117 117 },
118 118 "search": [
119 119 "unlock"
120 120 ]
121 121 },
122 122 {
123 123 "uid": "b077586592b9b69166b981325446c836",
124 124 "css": "delete",
125 125 "code": 59392,
126 126 "src": "custom_icons",
127 127 "selected": true,
128 128 "svg": {
129 129 "path": "M515.4 92.3C303.8 92.3 130.8 265.4 130.8 476.9 130.8 688.5 303.8 861.5 515.4 861.5S900 688.5 900 476.9C900 265.4 726.9 92.3 515.4 92.3ZM742.3 507.7C742.3 523.1 730.8 534.6 711.5 534.6H315.4C300 534.6 284.6 523.1 284.6 507.7V446.2C284.6 430.8 296.2 419.2 315.4 419.2H711.5C726.9 419.2 742.3 430.8 742.3 446.2V507.7Z",
130 130 "width": 1000
131 131 },
132 132 "search": [
133 133 "delete"
134 134 ]
135 135 },
136 136 {
137 137 "uid": "dca63ad885c0d6f1780a8d1d55bc2380",
138 138 "css": "ok",
139 139 "code": 59393,
140 140 "src": "custom_icons",
141 141 "selected": true,
142 142 "svg": {
143 143 "path": "M515.4 115.4C303.8 115.4 130.8 288.5 130.8 500 130.8 711.5 303.8 884.6 515.4 884.6S900 711.5 900 500C900 288.5 726.9 115.4 515.4 115.4ZM753.8 411.5L450 715.4C438.5 726.9 423.1 726.9 411.5 715.4L273.1 576.9C261.5 565.4 261.5 550 273.1 538.5L315.4 496.2C326.9 484.6 342.3 484.6 353.8 496.2L411.5 553.8C423.1 565.4 438.5 565.4 450 553.8L669.2 334.6C680.8 323.1 696.2 323.1 707.7 334.6L750 376.9C765.4 384.6 765.4 400 753.8 411.5Z",
144 144 "width": 1000
145 145 },
146 146 "search": [
147 147 "ok"
148 148 ]
149 149 },
150 150 {
151 151 "uid": "c158b3a004c055c6ad1471cd98932268",
152 152 "css": "down",
153 153 "code": 59403,
154 154 "src": "custom_icons",
155 155 "selected": true,
156 156 "svg": {
157 157 "path": "M703.8 396.2L530.8 615.4C523.1 623.1 507.7 623.1 503.8 615.4L330.8 396.2C323.1 384.6 330.8 365.4 346.2 365.4H692.3C703.8 365.4 711.5 384.6 703.8 396.2Z",
158 158 "width": 1000
159 159 },
160 160 "search": [
161 161 "arrow_down"
162 162 ]
163 163 },
164 164 {
165 165 "uid": "02f59f392ad28056845cfc04cb121f13",
166 166 "css": "comment",
167 167 "code": 59394,
168 168 "src": "custom_icons",
169 169 "selected": true,
170 170 "svg": {
171 171 "path": "M130.8 784.6V280.8C130.8 207.7 188.5 150 261.5 150H769.2C842.3 150 900 207.7 900 280.8V569.2C900 642.3 842.3 700 769.2 700H273.1C269.2 700 261.5 703.8 257.7 707.7L165.4 800C153.8 815.4 130.8 803.8 130.8 784.6ZM261.5 211.5C223.1 211.5 188.5 242.3 188.5 284.6V696.2L234.6 650C238.5 646.2 242.3 642.3 250 642.3H769.2C807.7 642.3 842.3 611.5 842.3 569.2V280.8C842.3 242.3 811.5 207.7 769.2 207.7H261.5Z",
172 172 "width": 1000
173 173 },
174 174 "search": [
175 175 "comment"
176 176 ]
177 177 },
178 178 {
179 179 "uid": "9a44b838872ca62b8aba7bbbbf67cc59",
180 180 "css": "feed",
181 181 "code": 59400,
182 182 "src": "custom_icons",
183 183 "selected": true,
184 184 "svg": {
185 185 "path": "M842.3 111.5H188.5C153.8 111.5 130.8 138.5 130.8 169.2V826.9C130.8 857.7 157.7 884.6 188.5 884.6H846.2C876.9 884.6 903.8 857.7 903.8 826.9V169.2C900 138.5 873.1 111.5 842.3 111.5ZM307.7 776.9C269.2 776.9 234.6 746.2 234.6 703.8S265.4 630.8 307.7 630.8C346.2 630.8 380.8 661.5 380.8 703.8S346.2 776.9 307.7 776.9ZM553.8 788.5C519.2 788.5 496.2 761.5 496.2 730.8 496.2 619.2 407.7 530.8 296.2 530.8 265.4 530.8 230.8 503.8 230.8 473.1 230.8 438.5 253.8 411.5 284.6 411.5L296.2 411.5C473.1 411.5 615.4 553.8 615.4 730.8 611.5 761.5 584.6 788.5 553.8 788.5ZM750 788.5C715.4 788.5 692.3 761.5 692.3 730.8 692.3 511.5 511.5 330.8 292.3 330.8 261.5 330.8 226.9 303.8 226.9 269.2 226.9 234.6 250 207.7 280.8 207.7L292.3 207.7C576.9 207.7 811.5 438.5 811.5 726.9 811.5 761.5 784.6 788.5 750 788.5Z",
186 186 "width": 1000
187 187 },
188 188 "search": [
189 189 "feed"
190 190 ]
191 191 },
192 192 {
193 193 "uid": "e0118d6f20b76d77317977ae8dc849d7",
194 194 "css": "left",
195 195 "code": 59401,
196 196 "src": "custom_icons",
197 197 "selected": true,
198 198 "svg": {
199 199 "path": "M692.3 76.9L761.5 146.2C773.1 157.7 773.1 173.1 761.5 184.6L473.1 473.1C461.5 484.6 461.5 500 473.1 511.5L769.2 807.7C780.8 819.2 780.8 834.6 769.2 846.2L700 915.4C688.5 926.9 673.1 926.9 661.5 915.4L257.7 511.5C246.2 500 246.2 484.6 257.7 473.1L653.8 76.9C665.4 65.4 680.8 65.4 692.3 76.9Z",
200 200 "width": 1000
201 201 },
202 202 "search": [
203 203 "left"
204 204 ]
205 205 },
206 206 {
207 207 "uid": "3cea97f90c8f2b0a90833855434f58de",
208 208 "css": "right",
209 209 "code": 59402,
210 210 "src": "custom_icons",
211 211 "selected": true,
212 212 "svg": {
213 213 "path": "M338.5 915.4L265.4 846.2C253.8 834.6 253.8 819.2 265.4 807.7L553.8 519.2C565.4 507.7 565.4 492.3 553.8 480.8L257.7 184.6C246.2 173.1 246.2 157.7 257.7 146.2L326.9 76.9C338.5 65.4 353.8 65.4 365.4 76.9L769.2 480.8C780.8 492.3 780.8 507.7 769.2 519.2L376.9 915.4C365.4 926.9 346.2 926.9 338.5 915.4Z",
214 214 "width": 1000
215 215 },
216 216 "search": [
217 217 "right"
218 218 ]
219 219 },
220 220 {
221 221 "uid": "820a44cb2e7fc1d0e28b1d2a8cd44cb9",
222 222 "css": "git",
223 223 "code": 59434,
224 224 "src": "custom_icons",
225 225 "selected": true,
226 226 "svg": {
227 227 "path": "M928.8 6.3H71.3C35 6.3 6.3 36.3 6.3 71.3V927.5C6.3 963.8 36.3 992.5 71.3 992.5H927.5C963.8 992.5 992.5 962.5 992.5 927.5V71.3C993.8 36.3 963.7 6.3 928.8 6.3ZM200 555C203.8 566.3 208.8 575 213.8 582.5 220 590 227.5 596.3 236.3 600 245 603.8 255 606.3 265 606.3 273.8 606.3 281.3 605 288.8 603.8 296.3 602.5 302.5 600 308.8 597.5L315 546.3H287.5C283.8 546.3 280 545 277.5 542.5 276.3 541.3 275 537.5 275 535L280 496.2H385L368.7 627.5C361.2 633.8 352.5 638.7 343.7 642.5 335 646.3 326.3 650 316.2 652.5 306.2 655 297.5 657.5 286.3 658.8 276.3 660 265 661.3 252.5 661.3 232.5 661.3 215 657.5 198.7 650 182.5 642.5 168.7 632.5 157.5 620 146.2 607.5 137.5 592.5 131.2 575 125 557.5 121.2 538.8 121.2 518.8 121.2 501.3 123.7 485 127.5 468.8 131.2 452.5 137.5 438.8 145 425 152.5 411.3 161.2 400 171.2 388.8 181.2 377.5 192.5 368.8 205 361.3 217.5 353.8 231.3 347.5 246.3 343.8 261.3 340 276.3 337.5 292.5 337.5 306.3 337.5 317.5 338.8 328.7 341.3 340 343.8 350 347.5 357.5 351.3 366.2 355 373.8 360 380 365 386.3 370 392.5 376.3 397.5 381.3L377.5 412.5C373.8 417.5 368.8 420 363.8 421.3 358.8 422.5 353.7 421.3 347.5 417.5 342.5 413.8 337.5 411.3 333.7 408.8 328.7 406.3 325 403.8 320 402.5 315 401.3 310 400 305 398.8 300 397.5 293.7 397.5 287.5 397.5 273.7 397.5 261.2 400 250 406.3 238.7 412.5 228.7 420 221.2 431.3 212.5 441.2 206.2 455 202.5 468.8 197.5 483.8 196.2 500 196.2 517.5 195 531.3 197.5 543.8 200 555ZM536.3 657.5H465L503.7 342.5H575L536.3 657.5ZM878.8 398.8H798.8L766.3 657.5H696.3L727.5 398.7H647.5L655 342.5H886.3L878.8 398.8Z",
228 228 "width": 1000
229 229 },
230 230 "search": [
231 231 "git"
232 232 ]
233 233 },
234 234 {
235 235 "uid": "ea152b092f5ad7d610de2c388553e188",
236 236 "css": "hg",
237 237 "code": 59437,
238 238 "src": "custom_icons",
239 239 "selected": true,
240 240 "svg": {
241 241 "path": "M926.6 9.2H73.9C37.9 9.2 8.7 38.5 8.7 74.4V927.1C8.7 963.1 38 992.3 73.9 992.3H926.6C962.6 992.3 991.8 963 991.8 927.1V74.4C991.8 38.4 962.6 9.2 926.6 9.2ZM444 657.4H373.5L389.8 524.1H276.7L260.4 657.4H189.9L228.6 344.2H299.1L282.8 476.4H395.9L412.2 344.2H482.7L444 657.4ZM621 555.8C624.3 566.8 629.1 576 635.3 583.5 641.5 591 648.8 596.8 657.5 600.8 666.1 604.8 675.6 606.8 686.1 606.8 694.7 606.8 702.4 606 709.3 604.5 716.2 603 722.8 600.8 729.1 598.1L735.1 546.9H708.4C704.1 546.9 700.8 545.8 698.6 543.6 696.4 541.4 695.5 538.5 695.9 534.9L700.6 496.2H805.1L788.8 627.1C780.8 633 772.5 638.1 763.9 642.3 755.3 646.6 746.3 650 736.9 652.7 727.5 655.5 717.6 657.5 707.2 658.7 696.8 660 685.7 660.6 674 660.6 654.6 660.6 637 657 621 650 605 642.9 591.3 633.1 579.9 620.7 568.5 608.2 559.7 593.5 553.5 576.4 547.2 559.3 544.1 540.9 544.1 520.9 544.1 503.6 546.1 487.1 550 471.3 554 455.6 559.6 441.1 566.9 427.8 574.2 414.5 583 402.4 593.2 391.7 603.4 381 614.9 371.8 627.4 364.2 639.9 356.6 653.5 350.7 667.9 346.6 682.4 342.6 697.6 340.5 713.5 340.5 726.8 340.5 738.9 341.7 749.7 344.2 760.5 346.6 770.2 349.9 778.8 353.9 787.4 358 795.1 362.8 801.8 368.1 808.6 373.5 814.5 379 819.7 384.8L797 413.2C793.3 418.2 788.8 421.3 783.7 422.3 778.6 423.4 773.2 422.2 767.8 418.8 762.8 415.4 758.1 412.4 753.6 409.9 749.2 407.4 744.7 405.3 740.1 403.7 735.5 402 730.7 400.8 725.6 400 720.5 399.2 714.8 398.8 708.5 398.8 694.9 398.8 682.4 401.7 671.1 407.5 659.8 413.3 650 421.5 641.9 432 633.7 442.5 627.4 455.2 622.9 469.9 618.4 484.7 616.1 501 616.1 518.7 615.9 532.5 617.6 544.8 621 555.8Z",
242 242 "width": 1000
243 243 },
244 244 "search": [
245 245 "hg"
246 246 ]
247 247 },
248 248 {
249 249 "uid": "4a842c0afb4c35dacd21da71f9fed3f1",
250 250 "css": "comment-add",
251 251 "code": 59439,
252 252 "src": "custom_icons",
253 253 "selected": true,
254 254 "svg": {
255 255 "path": "M952.4 591.9V274.9C952.4 268.4 952.3 261.9 951.8 255.4 950.7 242.9 948.2 230.6 944.1 218.8 936.5 196.6 923.8 176.2 907.3 159.6 890.8 143.1 870.6 130.4 848.5 122.7 836.6 118.6 824.2 115.9 811.6 114.8 805.3 114.2 798.9 114.2 792.6 114.2H216.9C204 114.2 191.3 114.1 178.5 116 166.3 117.9 154.4 121.2 143 125.9 121.4 134.8 101.9 148.7 86.4 166.2 70.8 183.8 59.3 205 53.1 227.7 49.7 240.1 47.9 252.8 47.6 265.6 47.3 278.7 47.6 291.8 47.6 304.9V861.8C47.6 870.7 52.5 878.6 60.5 882.5 67.3 885.9 75.6 886.2 82.4 882.7 84.8 881.5 86.9 879.7 88.8 877.8 91.1 875.5 93.4 873.2 95.6 871 100.3 866.3 105 861.6 109.7 856.9L137.9 828.6C147.3 819.2 156.6 809.9 166 800.5 175.2 791.3 184.6 782.1 193.7 772.7 197.7 768.5 201.9 764.4 207.6 762.7 210.4 761.9 213.2 761.8 216 761.8H782.7C795.5 761.8 808.3 762 821 760.1 844.8 756.5 867.7 747.3 887.3 733.3 906.2 719.9 922.1 702.1 933.2 681.8 945.1 660.2 951.5 636 952.2 611.4 952.5 604.9 952.4 598.4 952.4 591.9ZM883.4 285.1V602.5C883.4 608.8 883.4 615.1 882.5 621.4 881.7 627.5 880.2 633.6 878.1 639.4 874.4 649.4 868.8 658.7 861.7 666.7 846.6 683.6 825.1 693.8 802.5 695.1 796.3 695.4 790 695.2 783.8 695.2H207.8C201.2 695.2 194.7 695.2 188.1 695.2 185 695.2 181.8 695.2 178.8 696.1 176.2 696.9 173.9 698.2 171.8 699.9 169.6 701.7 167.6 703.7 165.6 705.7 163.3 708 161 710.3 158.7 712.6 154 717.3 149.4 721.9 144.7 726.6 135.3 736 126 745.3 116.6 754.7V270C116.6 257.8 118.8 245.7 123.7 234.6 128 224.9 134 215.9 141.5 208.4 157.5 192.4 179.6 183.3 202.2 183.3H791.5C797.6 183.3 803.7 183.3 809.7 184.2 832 187.4 852.4 199.4 866 217.4 872.8 226.4 877.7 236.7 880.5 247.6 882 253.5 882.9 259.6 883.1 265.8 883.6 272.2 883.4 278.7 883.4 285.1ZM668.8 402H538.2C534.4 402 526.7 394.3 526.7 390.5V263.7C526.7 256 519 248.3 515.2 248.3H465.3C457.6 248.3 449.9 256 449.9 259.8V390.4C449.9 394.2 442.2 401.9 438.4 401.9H311.7C304 401.9 296.3 409.6 296.3 413.4V463.3C296.3 471 304 478.7 307.8 478.7H434.5C442.2 478.7 449.9 486.4 449.9 490.2V617C449.9 624.7 457.6 632.4 461.4 632.4H511.3C519 632.4 526.7 624.7 526.7 620.9V494.1C526.7 486.4 534.4 478.7 538.2 478.7H665C672.7 478.7 680.4 471 680.4 467.2V417.3C680.3 409.6 672.6 402 668.8 402Z",
256 256 "width": 1000
257 257 },
258 258 "search": [
259 259 "comment-add"
260 260 ]
261 261 },
262 262 {
263 263 "uid": "2427f6b8d4379b9a0b41cf31780807cf",
264 264 "css": "comment-toggle",
265 265 "code": 59440,
266 266 "src": "custom_icons",
267 267 "selected": true,
268 268 "svg": {
269 269 "path": "M797.6 114.2H202.4C116.6 114.2 47.6 183.3 47.6 269V861.9C47.6 881.4 69.5 891.1 84.1 881.8 86.4 880.7 88.6 879.1 90.6 877.1L199.8 768C202.1 765.7 204.7 764 207.7 762.8 209.7 762.2 211.9 761.9 214.3 761.9H797.6C883.4 761.9 952.4 692.8 952.4 607.1V269C952.4 183.2 883.3 114.2 797.6 114.2ZM118.3 752.6V269.5C118.3 222.5 156.4 184.3 203.5 184.3H680.1C593.7 267.9 175.5 695.4 171.4 699.5L118.3 752.6Z",
270 270 "width": 1000
271 271 },
272 272 "search": [
273 273 "comment-toggle"
274 274 ]
275 275 },
276 276 {
277 277 "uid": "6533bdc16ab201eb3f3b27ce989cab33",
278 278 "css": "folder-open-empty",
279 279 "code": 61717,
280 280 "src": "fontawesome"
281 281 },
282 282 {
283 283 "uid": "d64b34fac1d9923b7d29d1550b628ecd",
284 284 "css": "lock",
285 285 "code": 59398,
286 286 "src": "custom_icons",
287 287 "selected": true,
288 288 "svg": {
289 289 "path": "M812.5 424.1H758.9V317C758.9 308 758.9 303.6 758.9 299.1 758.9 294.6 758.9 290.2 758.9 285.7 758.9 281.3 758.9 281.3 758.9 276.8 758.9 267.9 758.9 263.4 754.5 254.5 754.5 250 754.5 250 750 245.5 750 236.6 745.5 232.1 741.1 223.2 741.1 223.2 741.1 218.8 736.6 218.8 732.1 209.8 727.7 200.9 723.2 192 723.2 192 718.8 187.5 718.8 187.5 723.2 178.6 718.8 169.6 714.3 165.2 714.3 160.7 709.8 160.7 709.8 156.3 705.4 151.8 700.9 142.9 696.4 138.4 696.4 138.4 692 133.9 692 133.9 683 125 678.6 120.5 669.6 111.6 669.6 111.6 665.2 111.6 665.2 107.1 660.7 102.7 651.8 98.2 642.9 93.8 638.4 93.8 638.4 89.3 633.9 89.3 629.5 84.8 620.5 80.4 616.1 80.4 611.6 80.4 611.6 75.9 607.1 75.9 598.2 71.4 589.3 67 580.4 67 580.4 67 580.4 67 580.4 67 571.4 62.5 562.5 62.5 549.1 58 544.6 58 544.6 58 540.2 58 535.7 58 535.7 58 531.3 58 531.3 58 526.8 58 526.8 58 526.8 58 522.3 58 522.3 58 522.3 58 522.3 58 522.3 58 522.3 58 522.3 58 522.3 58 517.9 58 513.4 58 513.4 58 513.4 58 508.9 58 508.9 58 504.5 58 504.5 58 500 58 500 58 500 58 500 58 495.5 58 491.1 58 491.1 58 491.1 58 491.1 58 491.1 58 491.1 58 491.1 58 491.1 58 491.1 58 486.6 58 486.6 58 486.6 58 482.1 58 482.1 58 477.7 58 477.7 58 473.2 58 468.8 58 468.8 58 464.3 58 455.4 58 442 62.5 433 67 433 67 433 67 433 67 410.7 67 397.3 71.4 388.4 75.9 383.9 75.9 383.9 80.4 379.5 80.4 375 84.8 370.5 84.8 361.6 89.3 361.6 93.8 357.1 93.8 357.1 93.8 348.2 98.2 339.3 102.7 334.8 111.6 334.8 111.6 330.4 111.6 330.4 116.1 321.4 120.5 317 125 308 133.9 308 133.9 303.6 138.4 303.6 138.4 299.1 142.9 294.6 151.8 290.2 156.3 290.2 160.7 285.7 160.7 285.7 165.2 276.8 169.6 272.3 178.6 272.3 183 267.9 183 267.9 187.5 267.9 187.5 263.4 196.4 258.9 205.4 254.5 214.3 254.5 214.3 254.5 218.8 250 218.8 250 232.1 245.5 236.6 245.5 245.5 245.5 250 245.5 250 241.1 254.5 241.1 263.4 236.6 267.9 236.6 276.8 236.6 281.3 236.6 281.3 236.6 285.7 236.6 290.2 236.6 294.6 236.6 299.1 236.6 303.6 236.6 312.5 236.6 317V424.1H187.5C169.6 424.1 160.7 437.5 160.7 450.9V915.2C160.7 933 174.1 942 187.5 942H808C825.9 942 834.8 928.6 834.8 915.2V450.9C839.3 433 825.9 424.1 812.5 424.1ZM361.6 317C361.6 250 410.7 196.4 473.2 183 473.2 183 473.2 183 477.7 183 486.6 183 491.1 183 500 183 500 183 504.5 183 504.5 183 504.5 183 504.5 183 504.5 183 513.4 183 517.9 183 526.8 183 526.8 183 526.8 183 531.3 183 593.8 196.4 642.9 250 642.9 317V424.1H361.6V317Z",
290 290 "width": 1000
291 291 },
292 292 "search": [
293 293 "lock"
294 294 ]
295 295 },
296 296 {
297 297 "uid": "d95fde5e3bfeb3302efc47c90538a1c5",
298 298 "css": "more",
299 299 "code": 59410,
300 300 "src": "custom_icons",
301 301 "selected": true,
302 302 "svg": {
303 303 "path": "M546.2 415.4H446.2C430.8 415.4 419.2 426.9 419.2 442.3V542.3C419.2 557.7 430.8 569.2 446.2 569.2H546.2C561.5 569.2 573.1 557.7 573.1 542.3V442.3C573.1 426.9 561.5 415.4 546.2 415.4ZM546.2 107.7H446.2C430.8 107.7 419.2 119.2 419.2 134.6V234.6C419.2 250 430.8 261.5 446.2 261.5H546.2C561.5 261.5 573.1 250 573.1 234.6V134.6C573.1 119.2 561.5 107.7 546.2 107.7ZM546.2 723.1H446.2C430.8 723.1 419.2 734.6 419.2 750V850C419.2 865.4 430.8 876.9 446.2 876.9H546.2C561.5 876.9 573.1 865.4 573.1 850V750C573.1 734.6 561.5 723.1 546.2 723.1Z",
304 304 "width": 1000
305 305 },
306 306 "search": [
307 307 "more"
308 308 ]
309 309 },
310 310 {
311 311 "uid": "34e7772638ae3ca1bfb0a4eca2c39221",
312 312 "css": "merge",
313 313 "code": 59443,
314 314 "src": "custom_icons",
315 315 "selected": true,
316 316 "svg": {
317 317 "path": "M199.8 740.5C199.8 812.2 258.1 870.5 329.8 870.5S459.8 812.2 459.8 740.5C459.8 694.6 435.8 654.5 399.8 631.3 418.4 491.7 533.4 451.9 602.4 440.6V742.4C563.7 765 537.4 806.4 537.4 854.4 537.4 926.1 595.7 984.4 667.4 984.4S797.4 926.1 797.4 854.4C797.4 806.5 771.1 765 732.4 742.4V254.9C771.1 232.3 797.4 190.9 797.4 142.9 797.4 71.2 739.1 12.9 667.4 12.9S537.4 71.2 537.4 142.9C537.4 190.8 563.7 232.3 602.4 254.9V309.9C542.2 317.8 440.4 342.3 364.2 417.8 309.5 472.1 277.9 542.1 269.6 625.9 228.4 647.7 199.8 690.6 199.8 740.5ZM667.6 897.8C643.7 897.8 624.3 878.3 624.3 854.5S643.8 811.2 667.6 811.2C691.5 811.2 710.9 830.7 710.9 854.5S691.5 897.8 667.6 897.8ZM667.6 99.6C691.5 99.6 710.9 119 710.9 142.9S691.4 186.2 667.6 186.2C643.7 186.2 624.3 166.8 624.3 142.9S643.7 99.6 667.6 99.6ZM329.9 783.9C306 783.9 286.6 764.4 286.6 740.6S306.1 697.3 329.9 697.3C353.8 697.3 373.2 716.7 373.2 740.6S353.8 783.9 329.9 783.9Z",
318 318 "width": 1000
319 319 },
320 320 "search": [
321 321 "merge"
322 322 ]
323 323 },
324 324 {
325 325 "uid": "c95735c17a10af81448c7fed98a04546",
326 326 "css": "folder-open",
327 327 "code": 59405,
328 328 "src": "fontawesome"
329 329 },
330 330 {
331 331 "uid": "865ac833a8efcfc24a6f573705ce56b1",
332 332 "css": "svn",
333 333 "code": 59438,
334 334 "src": "custom_icons",
335 335 "selected": true,
336 336 "svg": {
337 337 "path": "M933.4 9.2H80.7C44.7 9.2 15.5 38.5 15.5 74.4V927.1C15.5 963.1 44.8 992.3 80.7 992.3H933.4C969.4 992.3 998.6 963 998.6 927.1V74.4C998.7 38.4 969.4 9.2 933.4 9.2ZM167.9 447.1C171.1 451 175.4 454.4 180.8 457.3 186.2 460.2 192.2 463 199 465.4 205.7 467.8 212.7 470.5 219.8 473.3 226.9 476.2 233.9 479.5 240.7 483.2 247.5 486.9 253.6 491.6 259 497.2 264.4 502.8 268.7 509.6 271.9 517.4 275.1 525.3 276.8 534.8 276.8 545.8 276.8 561.6 274.1 576.4 268.6 590.3 263.1 604.3 255.3 616.4 245.1 626.8 234.9 637.2 222.5 645.4 208 651.5 193.4 657.6 177 660.7 158.8 660.7 149.7 660.7 140.7 659.7 131.5 657.7S113.6 652.8 105.2 649.2C96.8 645.5 89 641.2 81.8 636.2 74.6 631.2 68.5 625.6 63.5 619.5L88.5 586.7C90.5 584.3 93 582.3 95.9 580.7 98.8 579.1 101.8 578.3 104.8 578.3 108.8 578.3 112.7 579.7 116.5 582.5 120.3 585.3 124.5 588.4 129.1 591.8 133.7 595.2 139 598.2 145.1 601.1 151.2 603.9 158.7 605.3 167.6 605.3 180.7 605.3 190.7 601.7 197.8 594.7 204.9 587.6 208.4 577.1 208.4 563.2 208.4 556.8 206.8 551.4 203.5 547.3 200.3 543.1 196 539.7 190.8 536.8 185.6 533.9 179.6 531.4 172.8 529.1 166 526.9 159.2 524.5 152.1 521.9 145.1 519.3 138.2 516.2 131.4 512.8 124.6 509.3 118.6 504.7 113.4 499 108.2 493.3 103.9 486.4 100.7 478.2 97.5 469.9 95.9 459.8 95.9 447.7 95.9 433.8 98.5 420.4 103.7 407.6 108.9 394.8 116.4 383.4 126.2 373.5 136 363.6 147.8 355.7 161.7 349.8 175.6 343.9 191.3 341 208.6 341 217.5 341 226.1 341.9 234.5 343.8S250.8 348.2 258.1 351.6C265.4 354.9 272.1 358.8 278.1 363.3 284.1 367.8 289.2 372.8 293.4 378.1L272.3 407C269.7 410.3 267.2 412.8 264.8 414.4 262.4 416 259.4 416.8 256 416.8 252.7 416.8 249.4 415.8 246.1 413.6 242.8 411.4 239.1 409.1 235 406.5 230.9 403.9 226.2 401.6 220.9 399.4 215.6 397.2 209.3 396.2 202.2 396.2 195.6 396.2 189.8 397.1 184.9 399 179.9 400.9 175.8 403.4 172.5 406.8 169.2 410.1 166.7 414 165.1 418.4 163.5 422.9 162.6 427.8 162.6 433 163.1 438.4 164.7 443.2 167.9 447.1ZM480 657.4H416.3L339.2 343.7H395.6C401.6 343.7 406.4 345.1 410 348 413.6 350.8 415.8 354.5 416.7 359L449.4 531.8C451.3 538.7 453 546.3 454.6 554.8 456.2 563.2 457.5 571.9 458.7 581 461.7 572 464.9 563.2 468.4 554.8 471.8 546.4 475.4 538.8 479.2 531.8L552.3 359C553.2 357.1 554.4 355.2 556.1 353.4 557.7 351.5 559.6 349.8 561.8 348.4 564 347 566.4 345.8 569 345 571.6 344.2 574.4 343.7 577.3 343.7H634.1L480 657.4ZM902.6 657.4H866C860.5 657.4 856.1 656.5 852.8 654.7 849.4 652.9 846.2 649.9 843.2 645.8L733.6 452.2C733.3 456.2 733 460.1 732.7 463.8 732.3 467.6 732 471.1 731.7 474.4L710.2 657.4H648.2L686.9 343.7H723.9C726.9 343.7 729.5 343.8 731.6 344 733.7 344.2 735.5 344.7 737.1 345.5 738.7 346.3 740.1 347.4 741.4 348.8S744.1 352.1 745.5 354.4L855.5 548.1C855.8 543.1 856.2 538.3 856.7 533.7 857.2 529.2 857.8 524.8 858.3 520.8L879.4 343.6H941.4L902.6 657.4Z",
338 338 "width": 1000
339 339 },
340 340 "search": [
341 341 "svn"
342 342 ]
343 343 },
344 344 {
345 345 "uid": "bbfb51903f40597f0b70fd75bc7b5cac",
346 346 "css": "trash",
347 347 "code": 61944,
348 348 "src": "fontawesome"
349 349 },
350 350 {
351 351 "uid": "f48ae54adfb27d8ada53d0fd9e34ee10",
352 352 "css": "trash-empty",
353 353 "code": 59406,
354 354 "src": "fontawesome"
355 355 },
356 356 {
357 357 "uid": "f8aa663c489bcbd6e68ec8147dca841e",
358 358 "css": "folder",
359 359 "code": 59404,
360 360 "src": "fontawesome"
361 361 },
362 362 {
363 363 "uid": "c8585e1e5b0467f28b70bce765d5840c",
364 364 "css": "docs",
365 365 "code": 61637,
366 366 "src": "fontawesome"
367 367 },
368 368 {
369 369 "uid": "1b5a5d7b7e3c71437f5a26befdd045ed",
370 370 "css": "doc",
371 371 "code": 59414,
372 372 "src": "fontawesome"
373 373 },
374 374 {
375 375 "uid": "5408be43f7c42bccee419c6be53fdef5",
376 376 "css": "doc-text",
377 377 "code": 61686,
378 378 "src": "fontawesome"
379 379 },
380 380 {
381 381 "uid": "b091a8bd0fdade174951f17d936f51e4",
382 382 "css": "folder-empty",
383 383 "code": 61716,
384 384 "src": "fontawesome"
385 385 },
386 386 {
387 387 "uid": "c08a1cde48d96cba21d8c05fa7d7feb1",
388 388 "css": "doc-text-inv",
389 389 "code": 61788,
390 390 "src": "fontawesome"
391 391 },
392 392 {
393 393 "uid": "178053298e3e5b03551d754d4b9acd8b",
394 394 "css": "doc-inv",
395 395 "code": 61787,
396 396 "src": "fontawesome"
397 397 },
398 398 {
399 399 "uid": "e99461abfef3923546da8d745372c995",
400 400 "css": "cog",
401 401 "code": 59415,
402 402 "src": "fontawesome"
403 403 },
404 404 {
405 405 "uid": "98687378abd1faf8f6af97c254eb6cd6",
406 406 "css": "cog-alt",
407 407 "code": 59416,
408 408 "src": "fontawesome"
409 409 },
410 410 {
411 411 "uid": "21b42d3c3e6be44c3cc3d73042faa216",
412 412 "css": "sliders",
413 413 "code": 61918,
414 414 "src": "fontawesome"
415 415 },
416 416 {
417 417 "uid": "559647a6f430b3aeadbecd67194451dd",
418 418 "css": "menu",
419 419 "code": 61641,
420 420 "src": "fontawesome"
421 421 },
422 422 {
423 423 "uid": "c5fd349cbd3d23e4ade333789c29c729",
424 424 "css": "eye",
425 425 "code": 59417,
426 426 "src": "fontawesome"
427 427 },
428 428 {
429 429 "uid": "7fd683b2c518ceb9e5fa6757f2276faa",
430 430 "css": "eye-off",
431 431 "code": 59418,
432 432 "src": "fontawesome"
433 433 },
434 434 {
435 435 "uid": "2e2dba0307a502a8507c1729084c7ab5",
436 436 "css": "cancel-circled2",
437 437 "code": 59419,
438 438 "src": "fontawesome"
439 439 },
440 440 {
441 441 "uid": "0f4cae16f34ae243a6144c18a003f2d8",
442 442 "css": "cancel-circled",
443 443 "code": 59420,
444 444 "src": "fontawesome"
445 445 },
446 446 {
447 447 "uid": "26613a2e6bc41593c54bead46f8c8ee3",
448 448 "css": "file-code",
449 449 "code": 61897,
450 450 "src": "fontawesome"
451 451 },
452 452 {
453 453 "uid": "5211af474d3a9848f67f945e2ccaf143",
454 454 "css": "remove",
455 455 "code": 59408,
456 456 "src": "fontawesome"
457 457 },
458 458 {
459 459 "uid": "44e04715aecbca7f266a17d5a7863c68",
460 460 "css": "plus",
461 461 "code": 59421,
462 462 "src": "fontawesome"
463 463 },
464 464 {
465 465 "uid": "4ba33d2607902cf690dd45df09774cb0",
466 466 "css": "plus-circled",
467 467 "code": 59422,
468 468 "src": "fontawesome"
469 469 },
470 470 {
471 471 "uid": "1a5cfa186647e8c929c2b17b9fc4dac1",
472 472 "css": "plus-squared",
473 473 "code": 61694,
474 474 "src": "fontawesome"
475 475 },
476 476 {
477 477 "uid": "2d3be3e856fc1e4ac067590d2ded1b07",
478 478 "css": "plus-squared-alt",
479 479 "code": 61846,
480 480 "src": "fontawesome"
481 481 },
482 482 {
483 483 "uid": "eeadb020bb75d089b25d8424aabe19e0",
484 484 "css": "minus-circled",
485 485 "code": 59423,
486 486 "src": "fontawesome"
487 487 },
488 488 {
489 489 "uid": "f755a58fb985eeb70bd47d9b31892a34",
490 490 "css": "minus-squared",
491 491 "code": 61766,
492 492 "src": "fontawesome"
493 493 },
494 494 {
495 495 "uid": "18ef25350258541e8e54148ed79845c0",
496 496 "css": "minus-squared-alt",
497 497 "code": 61767,
498 498 "src": "fontawesome"
499 499 },
500 500 {
501 501 "uid": "861ab06e455e2de3232ebef67d60d708",
502 502 "css": "minus",
503 503 "code": 59424,
504 504 "src": "fontawesome"
505 505 },
506 506 {
507 507 "uid": "e82cedfa1d5f15b00c5a81c9bd731ea2",
508 508 "css": "info-circled",
509 509 "code": 59425,
510 510 "src": "fontawesome"
511 511 },
512 512 {
513 513 "uid": "9dd9e835aebe1060ba7190ad2b2ed951",
514 514 "css": "search",
515 515 "code": 59411,
516 516 "src": "fontawesome"
517 517 },
518 518 {
519 519 "uid": "b429436ec5a518c78479d44ef18dbd60",
520 520 "css": "paste",
521 521 "code": 61674,
522 522 "src": "fontawesome"
523 523 },
524 524 {
525 525 "uid": "8772331a9fec983cdb5d72902a6f9e0e",
526 526 "css": "scissors",
527 527 "code": 59412,
528 528 "src": "fontawesome"
529 529 },
530 530 {
531 531 "uid": "9a76bc135eac17d2c8b8ad4a5774fc87",
532 532 "css": "download",
533 533 "code": 59413,
534 534 "src": "fontawesome"
535 535 },
536 536 {
537 537 "uid": "eeec3208c90b7b48e804919d0d2d4a41",
538 538 "css": "upload",
539 539 "code": 59426,
540 540 "src": "fontawesome"
541 541 },
542 542 {
543 543 "uid": "5d2d07f112b8de19f2c0dbfec3e42c05",
544 544 "css": "spin",
545 545 "code": 59448,
546 546 "src": "fontelico"
547 547 },
548 548 {
549 549 "uid": "9bd60140934a1eb9236fd7a8ab1ff6ba",
550 550 "css": "spin-alt",
551 551 "code": 59444,
552 552 "src": "fontelico"
553 553 },
554 554 {
555 "uid": "513ac180ff85bd275f2b736720cbbf5e",
556 "css": "home",
557 "code": 59427,
558 "src": "entypo"
559 },
560 {
555 561 "uid": "c43db6645e7515889fc2193294f50767",
556 562 "css": "plus",
557 563 "code": 59411,
558 564 "src": "custom_icons",
559 565 "selected": false,
560 566 "svg": {
561 567 "path": "M873.1 446.2H619.2C603.8 446.2 592.3 434.6 592.3 419.2V165.4C592.3 150 580.8 138.5 565.4 138.5H465.4C450 138.5 438.5 150 438.5 165.4V419.2C438.5 434.6 426.9 446.2 411.5 446.2H157.7C142.3 446.2 130.8 457.7 130.8 473.1V573.1C130.8 588.5 142.3 600 157.7 600H411.5C426.9 600 438.5 611.5 438.5 626.9V880.8C438.5 896.2 450 907.7 465.4 907.7H565.4C580.8 907.7 592.3 896.2 592.3 880.8V626.9C592.3 611.5 603.8 600 619.2 600H873.1C888.5 600 900 588.5 900 573.1V473.1C900 457.7 888.5 446.2 873.1 446.2Z",
562 568 "width": 1000
563 569 },
564 570 "search": [
565 571 "plus"
566 572 ]
567 573 },
568 574 {
569 575 "uid": "7d7f338d90203f20c0d8d5c26091cc69",
570 576 "css": "minus",
571 577 "code": 59412,
572 578 "src": "custom_icons",
573 579 "selected": false,
574 580 "svg": {
575 581 "path": "M980 560H20C10 560 0 550 0 540V380C0 370 10 360 20 360H985C995 360 1005 370 1005 380V545C1000 550 990 560 980 560Z",
576 582 "width": 1000
577 583 },
578 584 "search": [
579 585 "minus"
580 586 ]
581 587 },
582 588 {
583 589 "uid": "4ccc61480001600f2e7e3c7dd0546c6e",
584 590 "css": "remove",
585 591 "code": 59413,
586 592 "src": "custom_icons",
587 593 "selected": false,
588 594 "svg": {
589 595 "path": "M975 140L860 25C845 10 825 10 810 25L525 310C510 325 490 325 475 310L190 25C175 10 155 10 140 25L25 140C10 155 10 175 25 190L310 475C325 490 325 510 310 525L25 810C10 825 10 845 25 860L140 975C155 990 175 990 190 975L475 690C490 675 510 675 525 690L810 975C825 990 845 990 860 975L975 860C990 845 990 825 975 810L690 525C675 510 675 490 690 475L975 190C990 180 990 155 975 140Z",
590 596 "width": 1000
591 597 },
592 598 "search": [
593 599 "remove"
594 600 ]
595 601 }
596 602 ]
597 603 } No newline at end of file
1 NO CONTENT: modified file, binary diff hidden
@@ -1,130 +1,132 b''
1 1 <?xml version="1.0" standalone="no"?>
2 2 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 3 <svg xmlns="http://www.w3.org/2000/svg">
4 4 <metadata>Copyright (C) 2019 by original authors @ fontello.com</metadata>
5 5 <defs>
6 6 <font id="rcicons" horiz-adv-x="1000" >
7 7 <font-face font-family="rcicons" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
8 8 <missing-glyph horiz-adv-x="1000" />
9 9 <glyph glyph-name="delete" unicode="&#xe800;" d="M515 758c-211 0-384-173-384-385 0-211 173-385 384-385s385 174 385 385c0 212-173 385-385 385z m227-416c0-15-11-27-30-27h-397c-15 0-30 12-30 27v62c0 15 11 27 30 27h397c15 0 30-12 30-27v-62z" horiz-adv-x="1000" />
10 10
11 11 <glyph glyph-name="ok" unicode="&#xe801;" d="M515 735c-211 0-384-173-384-385 0-211 173-385 384-385s385 174 385 385c0 212-173 385-385 385z m239-296l-304-304c-11-12-27-12-38 0l-139 138c-11 12-11 27 0 39l42 42c12 11 27 11 39 0l58-58c11-11 27-11 38 0l219 219c12 12 27 12 39 0l42-42c15-8 15-23 4-34z" horiz-adv-x="1000" />
12 12
13 13 <glyph glyph-name="comment" unicode="&#xe802;" d="M131 65v504c0 73 58 131 131 131h507c73 0 131-58 131-131v-288c0-73-58-131-131-131h-496c-4 0-11-4-15-8l-93-92c-11-15-34-4-34 15z m131 574c-39 0-73-31-73-74v-411l46 46c4 4 7 8 15 8h519c39 0 73 31 73 73v288c0 39-30 73-73 73h-507z" horiz-adv-x="1000" />
14 14
15 15 <glyph glyph-name="bookmark" unicode="&#xe803;" d="M780-140l-260 290c-10 10-25 10-35 0l-260-295c-20-20-45-5-45 30v930c-5 20 10 35 25 35h590c15 0 30-15 30-35v-925c0-35-30-50-45-30z" horiz-adv-x="1000" />
16 16
17 17 <glyph glyph-name="branch" unicode="&#xe804;" d="M875 600c0 76-58 134-134 134s-134-58-134-134c0-49 27-89 63-112-18-142-139-183-210-196v313c45 22 71 62 71 111 0 76-58 134-134 134s-134-58-134-134c0-49 27-94 67-116v-500c-40-22-67-67-67-116 0-76 58-134 134-134s134 58 134 134c0 49-26 94-67 116v58c63 9 166 31 246 112 58 58 89 129 98 214 40 22 67 67 67 116z m-478 161c27 0 45-18 45-45s-18-45-45-45-44 18-44 45 18 45 44 45z m0-822c-26 0-44 18-44 45s18 45 44 45 45-18 45-45-22-45-45-45z m344 706c27 0 45-18 45-45s-18-45-45-45-45 18-45 45 23 45 45 45z" horiz-adv-x="1000" />
18 18
19 19 <glyph glyph-name="tag" unicode="&#xe805;" d="M460 788l-366 8c-18 0-31-13-31-31l13-366c0-9 4-13 9-22l464-465c14-13 31-13 45 0l352 353c14 14 14 31 0 45l-468 469c-5 4-14 9-18 9z m-103-224c0-35-31-67-67-67-35 0-67 32-67 67 0 36 32 67 67 67s67-26 67-67z" horiz-adv-x="1000" />
20 20
21 21 <glyph glyph-name="lock" unicode="&#xe806;" d="M813 426h-54v107c0 9 0 13 0 18 0 4 0 9 0 13 0 5 0 5 0 9 0 9 0 14-4 23 0 4 0 4-5 9 0 8-4 13-9 22 0 0 0 4-4 4-5 9-9 18-14 27 0 0-4 5-4 5 4 8 0 17-5 22 0 4-4 4-4 9-5 4-9 13-14 18 0 0-4 4-4 4-9 9-13 14-22 22 0 0-5 0-5 5-4 4-13 9-22 13-5 0-5 5-9 5-4 4-13 9-18 9-4 0-4 4-9 4-9 5-18 9-27 9 0 0 0 0 0 0-9 5-17 5-31 9-4 0-4 0-9 0-4 0-4 0-9 0 0 0-4 0-4 0 0 0-5 0-5 0 0 0 0 0 0 0 0 0 0 0 0 0-4 0-9 0-9 0 0 0-4 0-4 0-4 0-4 0-9 0 0 0 0 0 0 0-4 0-9 0-9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0-4 0-4 0 0 0-5 0-5 0-4 0-4 0-9 0-4 0-4 0-9 0-9 0-22-4-31-9 0 0 0 0 0 0-22 0-36-4-45-9-4 0-4-4-8-4-5-5-9-5-18-9 0-5-5-5-5-5-9-4-18-9-22-18 0 0-5 0-5-4-9-4-13-9-22-18 0 0-4-4-4-4-5-5-9-14-14-18 0-5-4-5-4-9-9-5-14-14-14-18-4 0-4-4-4-4-5-9-9-18-13-27 0 0 0-5-5-5 0-13-4-18-4-26 0-5 0-5-5-9 0-9-4-14-4-23 0-4 0-4 0-9 0-4 0-9 0-13 0-5 0-13 0-18v-107h-49c-18 0-27-13-27-27v-464c0-18 13-27 27-27h620c18 0 27 13 27 27v464c4 18-9 27-22 27z m-451 107c0 67 49 121 111 134 0 0 0 0 5 0 9 0 13 0 22 0 0 0 5 0 5 0 0 0 0 0 0 0 8 0 13 0 22 0 0 0 0 0 4 0 63-13 112-67 112-134v-107h-281v107z" horiz-adv-x="1000" />
22 22
23 23 <glyph glyph-name="unlock" unicode="&#xe807;" d="M781 415h-385v93c0 57 43 104 96 115 0 0 0 0 4 0 8 0 12 0 19 0 0 0 4 0 4 0 0 0 0 0 4 0 8 0 16 0 23-4 0 0 0 0 0 0 8 0 12-4 19-7 0 0 4 0 4-4 4-4 12-4 16-8 0 0 0 0 0 0 4-4 11-8 15-11 0 0 4-4 4-4 4-4 8-8 11-12 0 0 0 0 4-4 4-4 8-11 12-19 0 0 0-4 0-4 4-4 4-11 4-15 0 0 0-4 0-4 0 0 0 0 0-4 4-11 11-19 23-19h57c16 0 27 11 24 27 0 0 0 0 0 0 0 0 0 4 0 4 0 7-4 11-4 19 0 4 0 4-4 8 0 15 0 19-4 27 0 0 0 3-4 3-4 8-8 16-11 23 0 0-4 4-4 4-4 8-8 12-12 16 0 4-4 4-4 7-3 4-7 12-11 16 0 0-4 4-4 4-8 7-12 11-19 19 0 0-4 0-4 4-4 4-12 7-19 11-4 0-4 4-8 4-4 4-12 8-15 8-4 0-4 4-8 4-8 3-15 7-23 7 0 0 0 0 0 0-8 4-16 4-27 8-4 0-4 0-8 0-7 0-11 0-19 4-4 0-8 0-8 0-7 0-15 0-23 0 0 0-4 0-4 0-7 0-15-4-27-4-3 0-11-4-15-4 0 0-4 0-4 0-92-27-157-115-157-215v-93h-43c-15 0-23-11-23-23v-400c0-15 12-23 23-23h535c15 0 23 12 23 23v400c4 12-8 23-23 23z" horiz-adv-x="1000" />
24 24
25 25 <glyph glyph-name="feed" unicode="&#xe808;" d="M842 739h-653c-35 0-58-27-58-58v-658c0-31 27-58 58-58h657c31 0 58 27 58 58v658c-4 31-31 58-62 58z m-534-666c-39 0-73 31-73 73s30 73 73 73c38 0 73-30 73-73s-35-73-73-73z m246-11c-35 0-58 27-58 57 0 112-88 200-200 200-31 0-65 27-65 58 0 35 23 62 54 62l11 0c177 0 319-143 319-320-3-30-30-57-61-57z m196 0c-35 0-58 27-58 57 0 220-180 400-400 400-30 0-65 27-65 62 0 34 23 61 54 61l11 0c285 0 520-230 520-519 0-34-27-61-62-61z" horiz-adv-x="1000" />
26 26
27 27 <glyph glyph-name="left" unicode="&#xe809;" d="M692 773l70-69c11-12 11-27 0-39l-289-288c-11-12-11-27 0-38l296-297c12-11 12-27 0-38l-69-69c-11-12-27-12-38 0l-404 404c-12 11-12 26 0 38l396 396c11 12 27 12 38 0z" horiz-adv-x="1000" />
28 28
29 29 <glyph glyph-name="right" unicode="&#xe80a;" d="M339-65l-74 69c-11 11-11 27 0 38l289 289c11 11 11 27 0 38l-296 296c-12 12-12 27 0 39l69 69c12 12 27 12 38 0l404-404c12-11 12-27 0-38l-392-396c-12-12-31-12-38 0z" horiz-adv-x="1000" />
30 30
31 31 <glyph glyph-name="down" unicode="&#xe80b;" d="M704 454l-173-219c-8-8-23-8-27 0l-173 219c-8 11 0 31 15 31h346c12 0 20-20 12-31z" horiz-adv-x="1000" />
32 32
33 33 <glyph glyph-name="folder" unicode="&#xe80c;" d="M929 511v-393q0-51-37-88t-88-37h-679q-51 0-88 37t-37 88v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h375q51 0 88-37t37-88z" horiz-adv-x="928.6" />
34 34
35 35 <glyph glyph-name="folder-open" unicode="&#xe80d;" d="M1049 319q0-17-18-37l-187-221q-24-28-67-48t-81-20h-607q-19 0-33 7t-15 24q0 17 17 37l188 221q24 28 67 48t80 20h607q19 0 34-7t15-24z m-192 192v-90h-464q-53 0-110-26t-92-67l-188-221-2-3q0 2-1 7t0 7v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h303q52 0 88-37t37-88z" horiz-adv-x="1071.4" />
36 36
37 37 <glyph glyph-name="trash-empty" unicode="&#xe80e;" d="M286 439v-321q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q8 0 13-5t5-13z m143 0v-321q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q8 0 13-5t5-13z m142 0v-321q0-8-5-13t-12-5h-36q-8 0-13 5t-5 13v321q0 8 5 13t13 5h36q7 0 12-5t5-13z m72-404v529h-500v-529q0-12 4-22t8-15 6-5h464q2 0 6 5t8 15 4 22z m-375 601h250l-27 65q-4 5-9 6h-177q-6-1-10-6z m518-18v-36q0-8-5-13t-13-5h-54v-529q0-46-26-80t-63-34h-464q-37 0-63 33t-27 79v531h-53q-8 0-13 5t-5 13v36q0 8 5 13t13 5h172l39 93q9 21 31 35t44 15h178q23 0 44-15t30-35l39-93h173q8 0 13-5t5-13z" horiz-adv-x="785.7" />
38 38
39 39 <glyph glyph-name="group" unicode="&#xe80f;" d="M962 219v-15c0-4-4-12-12-12h-161-4c-16 20-39 39-77 43-35 7-54 15-69 23 7 7 19 11 30 15 46 8 58 23 66 35 7 11 7 23 0 38-8 16-31 43-31 81 0 38 0 104 73 104h8 7c73-4 77-66 73-104 0-38-23-69-30-81-8-15-8-27 0-38 7-12 23-27 65-35 54-4 62-46 62-54 0 0 0 0 0 0z m-708-15c15 15 38 31 69 35 39 7 62 15 73 26-7 8-19 16-34 20-47 7-58 23-66 34-7 12-7 23 0 39 8 15 31 42 31 81 0 38 0 103-73 103h-8-11c-73-3-77-65-73-103 0-39 23-70 30-81 8-16 8-27 0-39-7-11-23-27-65-34-46-8-54-50-54-54 0 0 0 0 0 0v-16c0-3 4-11 12-11h161 8z m454 11c-73 12-96 35-108 54-11 20-11 39 0 62 12 23 50 69 54 131 4 61 0 165-119 169h-16-15c-119-4-123-104-119-166 4-61 38-107 54-130 11-23 11-43 0-62-12-19-35-42-108-54-73-11-85-80-85-88 0 0 0 0 0 0v-23c0-8 8-16 16-16h257 258c8 0 15 8 15 16v23c0 0 0 0 0 0-3 4-11 73-84 84z" horiz-adv-x="1000" />
40 40
41 41 <glyph glyph-name="remove" unicode="&#xe810;" d="M724 112q0-22-15-38l-76-76q-16-15-38-15t-38 15l-164 165-164-165q-16-15-38-15t-38 15l-76 76q-16 16-16 38t16 38l164 164-164 164q-16 16-16 38t16 38l76 76q16 16 38 16t38-16l164-164 164 164q16 16 38 16t38-16l76-76q15-15 15-38t-15-38l-164-164 164-164q15-15 15-38z" horiz-adv-x="785.7" />
42 42
43 43 <glyph glyph-name="fork" unicode="&#xe811;" d="M792 654c0 58-46 100-100 100-57 0-100-46-100-100 0-35 20-65 47-85-12-84-70-123-127-142-58 15-116 54-127 142 27 20 46 50 46 85 0 58-46 100-100 100s-108-42-108-100c0-39 23-73 54-89 12-107 77-188 181-226v-162c-31-19-50-50-50-88 0-58 46-101 100-101s100 47 100 101c0 38-19 69-50 88v162c104 38 169 119 181 226 30 20 53 50 53 89z m-465 35c19 0 35-16 35-35s-16-31-35-31-35 12-35 31 16 35 35 35z m181-635c-19 0-35 15-35 35s16 34 35 34c19 0 34-15 34-34s-15-35-34-35z m184 635c20 0 35-16 35-35s-15-31-35-31-34 16-34 35 15 31 34 31z" horiz-adv-x="1000" />
44 44
45 45 <glyph glyph-name="more" unicode="&#xe812;" d="M546 435h-100c-15 0-27-12-27-27v-100c0-16 12-27 27-27h100c16 0 27 11 27 27v100c0 15-11 27-27 27z m0 307h-100c-15 0-27-11-27-27v-100c0-15 12-26 27-26h100c16 0 27 11 27 26v100c0 16-11 27-27 27z m0-615h-100c-15 0-27-12-27-27v-100c0-15 12-27 27-27h100c16 0 27 12 27 27v100c0 15-11 27-27 27z" horiz-adv-x="1000" />
46 46
47 47 <glyph glyph-name="search" unicode="&#xe813;" d="M643 386q0 103-73 176t-177 74-177-74-73-176 73-177 177-73 177 73 73 177z m286-465q0-29-22-50t-50-21q-30 0-50 21l-191 191q-100-69-223-69-80 0-153 31t-125 84-84 125-31 153 31 152 84 126 125 84 153 31 153-31 125-84 84-126 31-152q0-123-69-223l191-191q21-21 21-51z" horiz-adv-x="928.6" />
48 48
49 49 <glyph glyph-name="scissors" unicode="&#xe814;" d="M536 350q14 0 25-11t10-25-10-25-25-10-25 10-11 25 11 25 25 11z m167-36l283-222q16-11 14-31-3-20-19-28l-72-36q-7-4-16-4-10 0-17 4l-385 216-62-36q-4-3-7-3 8-28 6-54-4-43-31-83t-74-69q-74-47-154-47-76 0-124 44-51 47-44 116 4 42 31 82t73 69q74 47 155 47 46 0 84-18 5 8 13 13l68 40-68 41q-8 5-13 12-38-17-84-17-81 0-155 47-46 30-73 69t-31 82q-3 33 8 63t36 52q47 44 124 44 80 0 154-47 46-29 74-68t31-83q2-27-6-54 3-1 7-3l62-37 385 216q7 5 17 5 9 0 16-4l72-36q16-9 19-28 2-20-14-32z m-380 145q26 24 12 61t-59 65q-52 33-107 33-42 0-63-20-26-24-12-60t59-66q51-33 107-33 41 0 63 20z m-47-415q45 28 59 65t-12 60q-22 20-63 20-56 0-107-33-45-28-59-65t12-60q21-20 63-20 55 0 107 33z m99 342l54-33v7q0 20 18 31l8 4-44 26-15-14q-1-2-5-6t-7-7q-1-1-2-2t-2-1z m125-125l54-18 410 321-71 36-429-240v-64l-89-53 5-5q1-1 4-3 2-2 6-7t6-6l15-15z m393-232l71 35-290 228-99-77q-1-2-7-4z" horiz-adv-x="1000" />
50 50
51 51 <glyph glyph-name="download" unicode="&#xe815;" d="M714 100q0 15-10 25t-25 11-25-11-11-25 11-25 25-11 25 11 10 25z m143 0q0 15-10 25t-26 11-25-11-10-25 10-25 25-11 26 11 10 25z m72 125v-179q0-22-16-37t-38-16h-821q-23 0-38 16t-16 37v179q0 22 16 38t38 16h259l75-76q33-32 76-32t76 32l76 76h259q22 0 38-16t16-38z m-182 318q10-23-8-39l-250-250q-10-11-25-11t-25 11l-250 250q-17 16-8 39 10 21 33 21h143v250q0 15 11 25t25 11h143q14 0 25-11t10-25v-250h143q24 0 33-21z" horiz-adv-x="928.6" />
52 52
53 53 <glyph glyph-name="doc" unicode="&#xe816;" d="M819 638q16-16 27-42t11-50v-642q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h500q22 0 49-11t42-27z m-248 136v-210h210q-5 17-12 23l-175 175q-6 7-23 12z m215-853v572h-232q-23 0-38 16t-16 37v233h-429v-858h715z" horiz-adv-x="857.1" />
54 54
55 55 <glyph glyph-name="cog" unicode="&#xe817;" d="M571 350q0 59-41 101t-101 42-101-42-42-101 42-101 101-42 101 42 41 101z m286 61v-124q0-7-4-13t-11-7l-104-16q-10-30-21-51 19-27 59-77 6-6 6-13t-5-13q-15-21-55-61t-53-39q-7 0-14 5l-77 60q-25-13-51-21-9-76-16-104-4-16-20-16h-124q-8 0-14 5t-6 12l-16 103q-27 9-50 21l-79-60q-6-5-14-5-8 0-14 6-70 64-92 94-4 5-4 13 0 6 5 12 8 12 28 37t30 40q-15 28-23 55l-102 15q-7 1-11 7t-5 13v124q0 7 5 13t10 7l104 16q8 25 22 51-23 32-60 77-6 7-6 14 0 5 5 12 15 20 55 60t53 40q7 0 15-5l77-60q24 13 50 21 9 76 17 104 3 16 20 16h124q7 0 13-5t7-12l15-103q28-9 51-20l79 59q5 5 13 5 7 0 14-5 72-67 92-95 4-5 4-12 0-7-4-13-9-12-29-37t-30-40q15-28 23-54l102-16q7-1 12-7t4-13z" horiz-adv-x="857.1" />
56 56
57 57 <glyph glyph-name="cog-alt" unicode="&#xe818;" d="M500 350q0 59-42 101t-101 42-101-42-42-101 42-101 101-42 101 42 42 101z m429-286q0 29-22 51t-50 21-50-21-21-51q0-29 21-50t50-21 51 21 21 50z m0 572q0 29-22 50t-50 21-50-21-21-50q0-30 21-51t50-21 51 21 21 51z m-215-235v-103q0-6-4-11t-8-6l-87-14q-6-19-18-42 19-27 50-64 4-6 4-11 0-7-4-11-12-17-46-50t-43-33q-7 0-12 4l-64 50q-21-11-43-17-6-60-13-87-4-13-17-13h-104q-6 0-11 4t-5 10l-13 85q-19 6-42 18l-66-50q-4-4-11-4-6 0-12 4-80 75-80 90 0 5 4 10 5 8 23 30t26 34q-13 24-20 46l-85 13q-5 1-9 5t-4 11v104q0 5 4 10t9 6l86 14q7 19 18 42-19 27-50 64-4 6-4 11 0 7 4 12 12 16 46 49t44 33q6 0 12-4l64-50q19 10 43 18 6 60 13 86 3 13 16 13h104q6 0 11-4t6-10l13-85q19-6 42-17l65 49q5 4 12 4 6 0 11-4 81-75 81-90 0-4-4-10-7-9-24-30t-25-34q13-27 19-46l85-12q6-2 9-6t4-11z m357-298v-78q0-9-83-17-6-15-16-29 28-63 28-77 0-2-2-4-68-40-69-40-5 0-26 27t-29 37q-11-1-17-1t-17 1q-7-11-29-37t-25-27q-1 0-69 40-3 2-3 4 0 14 29 77-10 14-17 29-83 8-83 17v78q0 9 83 18 7 16 17 29-29 63-29 77 0 2 3 4 2 1 19 11t33 19 17 9q4 0 25-26t29-38q12 1 17 1t17-1q28 40 51 63l4 1q2 0 69-39 2-2 2-4 0-14-28-77 9-13 16-29 83-9 83-18z m0 572v-78q0-9-83-18-6-15-16-29 28-63 28-77 0-2-2-4-68-39-69-39-5 0-26 26t-29 38q-11-1-17-1t-17 1q-7-12-29-38t-25-26q-1 0-69 39-3 2-3 4 0 14 29 77-10 14-17 29-83 9-83 18v78q0 9 83 17 7 16 17 29-29 63-29 77 0 2 3 4 2 1 19 11t33 19 17 9q4 0 25-26t29-37q12 1 17 1t17-1q28 39 51 62l4 1q2 0 69-39 2-2 2-4 0-14-28-77 9-13 16-29 83-8 83-17z" horiz-adv-x="1071.4" />
58 58
59 59 <glyph glyph-name="eye" unicode="&#xe819;" d="M929 314q-85 132-213 197 34-58 34-125 0-103-73-177t-177-73-177 73-73 177q0 67 34 125-128-65-213-197 75-114 187-182t242-68 243 68 186 182z m-402 215q0 11-8 19t-19 7q-70 0-120-50t-50-119q0-11 8-19t19-8 19 8 8 19q0 48 34 82t82 34q11 0 19 8t8 19z m473-215q0-19-11-38-78-129-210-206t-279-77-279 77-210 206q-11 19-11 38t11 39q78 128 210 205t279 78 279-78 210-205q11-20 11-39z" horiz-adv-x="1000" />
60 60
61 61 <glyph glyph-name="eye-off" unicode="&#xe81a;" d="M310 105l43 79q-48 35-76 88t-27 114q0 67 34 125-128-65-213-197 94-144 239-209z m217 424q0 11-8 19t-19 7q-70 0-120-50t-50-119q0-11 8-19t19-8 19 8 8 19q0 48 34 82t82 34q11 0 19 8t8 19z m202 106q0-4 0-5-59-105-176-316t-176-316l-28-50q-5-9-15-9-7 0-75 39-9 6-9 16 0 7 25 49-80 36-147 96t-117 137q-11 17-11 38t11 39q86 131 212 207t277 76q50 0 100-10l31 54q5 9 15 9 3 0 10-3t18-9 18-10 18-10 10-7q9-5 9-15z m21-249q0-78-44-142t-117-91l157 280q4-25 4-47z m250-72q0-19-11-38-22-36-61-81-84-96-194-149t-234-53l41 74q119 10 219 76t169 171q-65 100-158 164l35 63q53-36 102-85t81-103q11-19 11-39z" horiz-adv-x="1000" />
62 62
63 63 <glyph glyph-name="cancel-circled2" unicode="&#xe81b;" d="M612 248l-81-82q-6-5-13-5t-13 5l-76 77-77-77q-5-5-13-5t-12 5l-82 82q-6 6-6 13t6 13l76 76-76 77q-6 5-6 12t6 13l82 82q5 5 12 5t13-5l77-77 76 77q6 5 13 5t13-5l81-82q6-5 6-13t-6-12l-76-77 76-76q6-6 6-13t-6-13z m120 102q0 83-41 152t-110 111-152 41-153-41-110-111-41-152 41-152 110-111 153-41 152 41 110 111 41 152z m125 0q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
64 64
65 65 <glyph glyph-name="cancel-circled" unicode="&#xe81c;" d="M641 224q0 14-10 25l-101 101 101 101q10 11 10 25 0 15-10 26l-51 50q-10 11-25 11-15 0-25-11l-101-101-101 101q-11 11-25 11-16 0-26-11l-50-50q-11-11-11-26 0-14 11-25l101-101-101-101q-11-11-11-25 0-15 11-26l50-50q10-11 26-11 14 0 25 11l101 101 101-101q10-11 25-11 15 0 25 11l51 50q10 11 10 26z m216 126q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
66 66
67 67 <glyph glyph-name="plus" unicode="&#xe81d;" d="M786 439v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q23 0 38-16t16-38z" horiz-adv-x="785.7" />
68 68
69 69 <glyph glyph-name="plus-circled" unicode="&#xe81e;" d="M679 314v72q0 14-11 25t-25 10h-143v143q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-143h-143q-14 0-25-10t-10-25v-72q0-14 10-25t25-10h143v-143q0-15 11-25t25-11h71q15 0 25 11t11 25v143h143q14 0 25 10t11 25z m178 36q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
70 70
71 71 <glyph glyph-name="minus-circled" unicode="&#xe81f;" d="M679 314v72q0 14-11 25t-25 10h-429q-14 0-25-10t-10-25v-72q0-14 10-25t25-10h429q14 0 25 10t11 25z m178 36q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
72 72
73 73 <glyph glyph-name="minus" unicode="&#xe820;" d="M786 439v-107q0-22-16-38t-38-15h-678q-23 0-38 15t-16 38v107q0 23 16 38t38 16h678q23 0 38-16t16-38z" horiz-adv-x="785.7" />
74 74
75 75 <glyph glyph-name="info-circled" unicode="&#xe821;" d="M571 82v89q0 8-5 13t-12 5h-54v286q0 8-5 13t-13 5h-178q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h53v-179h-53q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h250q7 0 12 5t5 13z m-71 500v89q0 8-5 13t-13 5h-107q-8 0-13-5t-5-13v-89q0-8 5-13t13-5h107q8 0 13 5t5 13z m357-232q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
76 76
77 77 <glyph glyph-name="upload" unicode="&#xe822;" d="M714 29q0 14-10 25t-25 10-25-10-11-25 11-25 25-11 25 11 10 25z m143 0q0 14-10 25t-26 10-25-10-10-25 10-25 25-11 26 11 10 25z m72 125v-179q0-22-16-38t-38-16h-821q-23 0-38 16t-16 38v179q0 22 16 38t38 15h238q12-31 39-51t62-20h143q34 0 61 20t40 51h238q22 0 38-15t16-38z m-182 361q-9-22-33-22h-143v-250q0-15-10-25t-25-11h-143q-15 0-25 11t-11 25v250h-143q-23 0-33 22-9 22 8 39l250 250q10 10 25 10t25-10l250-250q18-17 8-39z" horiz-adv-x="928.6" />
78 78
79 <glyph glyph-name="home" unicode="&#xe823;" d="M888 336q16-16 11-27t-27-11l-84 0 0-310q0-14-1-21t-8-13-23-6l-204 0 0 310-204 0 0-310-194 0q-28 0-35 10t-7 30l0 310-84 0q-22 0-27 11t11 27l400 402q16 16 38 16t38-16z" horiz-adv-x="900" />
80
79 81 <glyph glyph-name="git" unicode="&#xe82a;" d="M929 844h-858c-36 0-65-30-65-65v-857c0-36 30-65 65-65h857c36 0 65 30 65 65v857c1 35-29 65-64 65z m-729-549c4-11 9-20 14-27 6-8 14-14 22-18 9-4 19-6 29-6 9 0 16 1 24 2 7 2 14 4 20 7l6 51h-27c-4 0-8 1-10 4-2 1-3 5-3 7l5 39h105l-16-131c-8-7-16-12-25-15-9-4-18-8-28-10-10-3-18-5-30-7-10-1-21-2-33-2-20 0-38 4-54 11-16 8-30 18-41 30-12 13-20 28-27 45-6 18-10 36-10 56 0 18 3 34 7 50 3 17 10 30 17 44 8 14 16 25 26 36 10 12 22 20 34 28 13 7 26 14 41 17 15 4 30 7 47 7 13 0 25-2 36-4 11-3 21-6 29-10 8-4 16-9 22-14 6-5 13-11 18-16l-20-31c-4-5-9-8-14-9-5-1-10 0-16 4-5 3-10 6-14 8-5 3-9 5-14 7-5 1-10 2-15 3-5 2-11 2-17 2-14 0-27-3-38-9-11-6-21-14-29-25-8-10-15-24-18-38-5-15-7-31-7-48-1-14 2-27 4-38z m336-102h-71l39 315h71l-39-315z m343 258h-80l-33-258h-70l32 258h-80l7 57h231l-7-57z" horiz-adv-x="1000" />
80 82
81 83 <glyph glyph-name="hg" unicode="&#xe82d;" d="M927 841h-853c-36 0-65-29-65-65v-853c0-36 29-65 65-65h853c36 0 65 29 65 65v853c0 36-29 65-65 65z m-483-648h-70l16 133h-113l-17-133h-70l39 313h70l-16-132h113l16 132h71l-39-313z m177 101c3-11 8-20 14-27 7-8 14-14 23-18 8-4 18-6 28-6 9 0 16 1 23 3 7 1 14 3 20 6l6 51h-27c-4 0-7 1-9 3-3 3-3 6-3 9l5 39h104l-16-131c-8-6-16-11-25-15-9-5-18-8-27-11-9-2-19-4-30-6-10-1-21-2-33-2-19 0-37 4-53 11-16 7-30 17-41 29-11 13-20 28-26 45-7 17-10 35-10 55 0 17 2 34 6 50 4 15 10 30 17 43 7 14 16 26 26 36 10 11 22 20 34 28 13 7 27 13 41 17 14 4 30 7 46 7 13 0 25-2 36-4 11-3 20-6 29-10 8-4 16-9 23-14 7-5 13-11 18-17l-23-28c-4-5-8-8-13-9-5-1-11 0-16 3-5 4-10 7-14 9-5 3-9 5-14 6-4 2-9 3-14 4-5 1-11 1-17 1-14 0-27-3-38-8-11-6-21-14-29-25-8-10-15-23-19-38-5-15-7-31-7-49 0-13 2-26 5-37z" horiz-adv-x="1000" />
82 84
83 85 <glyph glyph-name="svn" unicode="&#xe82e;" d="M933 841h-852c-36 0-65-29-65-65v-853c0-36 29-65 65-65h852c36 0 66 29 66 65v853c0 36-30 65-66 65z m-765-438c3-4 7-7 13-10 5-3 11-6 18-8 7-3 14-5 21-8 7-3 14-6 21-10 7-4 13-9 18-14 5-6 10-13 13-20 3-8 5-18 5-29 0-16-3-30-8-44-6-14-14-26-24-37-10-10-22-18-37-24-15-7-31-10-49-10-9 0-18 1-27 3s-18 5-27 9c-8 4-16 8-23 13-7 5-13 10-18 17l25 32c2 3 4 5 7 6 3 2 6 3 9 3 4 0 8-2 12-4 3-3 8-6 12-10 5-3 10-6 16-9 6-3 14-4 23-4 13 0 23 3 30 10 7 7 10 18 10 32 0 6-1 12-4 16-4 4-8 7-13 10-5 3-11 6-18 8-7 2-14 5-21 7-7 3-14 6-21 9-6 4-12 8-18 14-5 6-9 13-12 21-3 8-5 18-5 30 0 14 3 28 8 40 5 13 12 25 22 35 10 9 22 17 36 23 14 6 29 9 47 9 9 0 17-1 26-3s16-4 23-8c7-3 14-7 20-11 6-5 11-10 15-15l-21-29c-2-3-5-6-7-7-3-2-6-3-9-3-3 0-7 1-10 3-3 3-7 5-11 8-4 2-9 4-14 7-5 2-12 3-19 3-6 0-12-1-17-3-5-2-9-4-12-8-4-3-6-7-8-11-1-5-2-10-2-15 0-5 2-10 5-14z m312-210h-64l-77 313h57c6 0 10-1 14-4 4-3 6-6 7-11l32-173c2-7 4-14 6-23 1-8 3-17 4-26 3 9 6 18 9 26 4 9 7 16 11 23l73 173c1 2 2 4 4 6 2 2 4 3 6 5 2 1 4 2 7 3 3 1 5 1 8 1h57l-154-313z m423 0h-37c-5 0-10 1-13 2-4 2-7 5-10 9l-109 194c-1-4-1-8-1-12-1-4-1-7-1-10l-22-183h-62l39 313h37c3 0 6 0 8 0 2 0 4-1 5-1 2-1 3-2 4-4s3-3 5-5l110-194c0 5 0 10 1 14 0 5 1 9 1 13l21 177h62l-38-313z" horiz-adv-x="1000" />
84 86
85 87 <glyph glyph-name="comment-add" unicode="&#xe82f;" d="M952 258v317c0 7 0 13 0 20-1 12-4 24-8 36-7 22-20 43-37 59-16 17-36 30-58 37-12 4-25 7-37 8-7 1-13 1-19 1h-576c-13 0-26 0-38-2-13-2-25-5-36-10-22-9-41-23-57-40-15-18-27-39-33-62-3-12-5-25-5-38-1-13 0-26 0-39v-557c0-9 5-17 13-21 6-3 15-3 21 0 3 1 5 3 7 5 2 2 4 5 7 7 4 5 9 9 14 14l28 28c9 10 19 19 28 29 9 9 19 18 28 27 4 5 8 9 14 10 2 1 5 1 8 1h567c13 0 25 0 38 2 24 4 47 13 66 27 19 13 35 31 46 51 12 22 19 46 19 71 1 6 0 13 0 19z m-69 307v-317c0-7 0-13 0-19-1-6-3-13-5-18-4-10-9-20-16-28-15-17-37-27-59-28-7 0-13 0-19 0h-576c-7 0-13 0-20 0-3 0-6 0-9-1-3-1-5-2-7-4-2-2-4-4-6-6-3-2-5-4-7-7-5-4-10-9-14-14-10-9-19-18-28-28v485c0 12 2 24 7 35 4 10 10 19 18 27 16 16 38 25 60 25h590c6 0 12 0 18-1 22-3 42-15 56-33 7-9 12-20 15-31 1-5 2-12 2-18 1-6 0-13 0-19z m-214-117h-131c-4 0-11 8-11 12v126c0 8-8 16-12 16h-50c-7 0-15-8-15-12v-130c0-4-8-12-12-12h-126c-8 0-16-8-16-11v-50c0-8 8-16 12-16h127c7 0 15-7 15-11v-127c0-8 8-15 11-15h50c8 0 16 7 16 11v127c0 8 7 15 11 15h127c8 0 15 8 15 12v50c0 7-7 15-11 15z" horiz-adv-x="1000" />
86 88
87 89 <glyph glyph-name="comment-toggle" unicode="&#xe830;" d="M798 736h-596c-85 0-154-69-154-155v-593c0-19 22-29 36-20 2 1 5 3 7 5l109 109c2 2 5 4 8 5 2 1 4 1 6 1h584c85 0 154 69 154 155v338c0 86-69 155-154 155z m-680-639v484c0 47 38 85 86 85h476c-86-84-504-511-509-515l-53-54z" horiz-adv-x="1000" />
88 90
89 91 <glyph glyph-name="rhodecode" unicode="&#xe831;" d="M175 633c-2-4-3-8-4-12-3-10-6-20-9-30-3-13-7-25-11-38-3-11-6-23-10-35-2-7-4-15-6-22-1-1-1-2-1-4 0 0 0 0 0 0 0-1 1-2 1-2 2-7 5-14 7-21 4-11 8-22 12-33 4-12 9-25 13-37 4-11 8-23 12-34 3-7 5-14 7-21 1-1 1-2 2-3 0-1 1-1 1-2 4-6 8-12 11-17 7-10 13-19 19-29 7-11 14-22 22-33 6-10 13-21 20-31 5-7 9-15 14-22 1-2 3-4 4-5 0-1 1-1 1-2 3-3 6-5 8-8 7-6 13-12 19-19 9-8 17-16 25-24 10-10 19-19 29-28 9-9 18-18 27-27 8-8 16-15 23-23 5-5 11-10 16-15 1-1 3-3 5-5 7-5 14-10 21-15 11-8 21-15 31-23 4-2 7-5 11-7 0-1 1-2 2-2 0 0 0-1 1 0 7 3 14 7 21 11 11 6 23 11 34 17 6 4 12 7 19 10 0 0 0 1 1 1 1 2 2 3 3 5 4 5 8 10 13 15 6 8 12 16 18 24 8 9 15 19 23 28 8 11 16 21 24 31 8 11 16 21 24 31 8 10 15 19 23 28 6 8 12 16 18 24 4 5 8 10 12 15 2 2 3 3 4 5 0 0 0 0 0 0-1 1-2 1-3 1-3 0-6 1-9 2-5 1-10 2-15 3-6 2-13 4-20 5-8 3-16 5-24 7-9 3-19 6-28 9-10 3-21 7-31 11-12 4-23 8-34 13-12 5-24 10-36 15-13 6-26 12-38 18-13 7-26 14-39 21-13 7-27 15-39 23-14 9-27 17-40 27-13 9-26 19-39 29-13 11-25 22-37 33-13 11-25 23-36 36-12 13-23 26-34 40-11 14-21 28-31 43-9 15-19 31-27 47 0 1 0 1 0 1z m-3 3c-1-5-3-9-4-14-3-10-7-21-10-32-4-12-8-25-12-37-3-10-6-20-9-30-1-3-2-6-3-8 0-1 0-2 0-2 1-5 3-10 5-15 3-10 6-20 10-30 4-12 8-24 12-37 4-12 8-24 12-36 3-9 6-18 9-26 1-3 1-5 2-8 0 0 1-1 1-2 2-4 5-8 7-12 5-10 10-19 15-28 6-11 12-23 19-34 6-11 12-22 18-33 4-8 8-15 12-23 1-2 2-4 4-6 4-5 8-9 13-14 7-8 15-16 23-24 9-10 18-20 26-29 9-9 17-18 25-26 5-6 10-11 15-17 2-1 3-3 5-5 5-5 11-11 17-17 9-8 17-17 26-26 9-9 18-18 27-27 7-7 14-14 21-21 2-2 3-3 5-5 0 0 1-1 1-1 0 0 1 0 1 0 11 2 22 3 32 5 9 1 17 2 26 3 0 0 1 1 1 1 1 1 2 3 4 4 4 5 9 10 13 15 7 8 14 15 20 22 9 9 17 18 25 27 9 10 18 20 27 30 8 9 17 19 26 29 8 9 16 17 24 26 7 7 13 15 20 22 4 5 8 9 13 14 1 1 2 2 3 3 0 1 1 1 1 1 0 1-3 1-3 1-3 1-7 2-10 3-4 2-9 3-14 5-6 2-13 4-19 6-8 3-16 6-24 9-9 3-18 7-27 11-10 4-20 8-30 13-11 5-22 10-33 16-12 5-23 11-35 18-12 6-24 13-36 20-12 8-25 16-37 24-13 8-25 17-37 26-13 10-25 19-38 29-12 11-24 21-36 33-12 11-24 23-35 35-11 13-22 25-33 39-10 13-21 27-30 42-10 15-19 30-27 45-9 16-17 32-24 48z m-2 10c-1-4-2-8-3-11-1-10-3-19-5-29-2-12-5-25-7-37-3-13-5-26-8-39-1-10-3-20-5-30-1-5-2-10-3-15 0-1 0-1 0-2 1-3 2-5 3-8 3-9 7-19 10-29 4-12 9-25 13-37 4-11 8-22 11-33 2-5 4-11 6-16 0-1 1-2 1-2 1-3 2-5 4-7 4-9 8-18 13-27 6-12 11-23 17-35 6-11 11-22 17-33 3-7 7-14 11-21 0-2 1-3 1-4 1-1 2-1 2-2 5-6 9-11 14-17 8-9 15-18 22-27 9-10 17-20 26-30 7-9 15-18 22-27 5-6 10-11 15-17 0-1 1-2 2-3 0 0 0 0 0 0 1-1 2-1 3-2 7-4 14-9 21-14 10-7 21-14 31-22 11-7 21-14 31-20 6-4 12-9 18-13 3-2 7-5 10-8 10-8 19-16 29-24 7-5 13-11 20-17 1 0 1 0 1 1 1 1 2 2 3 3 4 4 8 8 12 13 6 6 12 13 18 20 8 8 16 17 23 25 9 10 18 19 26 29 9 9 18 19 27 29 9 9 18 19 26 28 8 9 16 17 23 26 6 6 13 13 19 20 4 4 7 8 11 12 1 2 3 3 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0-3 1-3 1-3 1-6 2-9 2-5 2-10 4-15 5-6 2-12 5-18 7-8 3-16 6-24 9-8 4-17 8-26 12-10 4-20 9-30 13-11 6-22 11-32 16-12 6-23 13-35 19-12 7-23 14-35 21-13 8-25 16-37 24-12 8-25 17-37 26-12 9-24 19-36 29-13 10-25 21-36 32-12 11-24 22-35 34-12 12-22 25-33 38-11 13-21 26-30 40-10 14-19 29-28 44-9 15-17 30-24 46-4 10-8 20-12 30z m696 21c-2 4-5 7-9 9-5 3-11 5-16 8-11 4-23 9-34 13-23 8-47 14-71 20-24 6-49 12-74 17-25 6-50 10-76 15-25 4-50 8-75 10-13 1-26 1-39 0-6-1-13-2-19-3-6-1-13-2-19-3-26-4-51-9-77-14-25-5-50-10-75-16-25-5-49-12-74-20-12-4-24-9-36-13-6-3-11-5-17-8-3-1-6-2-9-3-3-1-5-2-8-4-4-2-7-5-10-9-1-2-2-4-3-7-1-3-2-6-3-9-4-11-7-24-9-36-5-24-7-49-6-74 0-13 1-25 3-38 1-12 3-25 5-37 5-25 12-50 20-74 4-12 8-24 13-36 4-11 10-22 15-33 10-21 21-42 34-62 12-20 25-39 39-58 14-19 28-37 43-55 16-18 33-36 50-54 17-18 34-35 52-52 18-17 36-33 55-49 10-7 19-15 28-22 10-8 19-15 28-23 2-2 5-4 7-7 0 0 1-1 1-1 0 0 1 0 1 0 0 0 1 0 2 0 4 4 9 8 14 11 9 8 19 15 28 23 18 15 36 31 54 47 18 16 35 32 52 49 17 16 33 34 49 51 16 18 32 37 47 56 14 18 28 38 41 57 13 20 25 40 36 61 11 21 21 43 30 65 9 22 17 45 23 68 6 23 11 47 13 70 3 24 3 49 2 73 0 3-1 6-2 9 0 3-1 6-2 9-1 6-2 12-3 18-3 11-5 22-8 33-4 9-7 19-11 28-2 5 13-29 0 0z m-51-210c-7-25-15-49-26-73-9-22-19-44-30-64-12-21-24-40-37-59-13-19-27-38-42-56-15-18-31-36-47-54-17-18-34-36-52-53-18-17-37-34-56-50-9-7-19-15-28-23-1 0-2-1-2-1-1 0-2 0-2 0-1 0-2 1-2 1 0 0-1 1-1 1-2 1-3 3-4 4-4 3-9 7-14 11-2 1-4 3-7 5-2 2-4 4-6 6-5 4-9 8-14 13-9 8-18 17-27 25-10 9-18 18-27 27-4 4-8 9-13 13-4 4-8 9-12 13-17 17-33 35-49 53-15 18-30 37-44 57-14 20-27 40-38 61-12 21-23 42-32 64-10 22-18 45-25 67-2 6-4 12-5 19-1 6-2 12-3 19-2 13-4 26-4 39-1 13-2 26-1 39 0 12 1 25 3 37 0 4 0 7 1 10 0 1 0 3 0 5 1 1 1 3 1 4 0 3 1 5 2 7 0 2 0 3 0 4 0 1 1 2 2 3 1 0 2 1 3 2 0 0 1 0 1 1 1 0 2 0 3 1 3 1 6 2 9 3 6 2 12 5 18 7 23 8 47 16 72 23 12 3 24 6 37 9 6 1 12 2 18 4 7 1 13 2 19 4 26 5 51 9 77 13 13 1 26 3 39 5 3 0 7 1 10 1 1 1 3 1 4 1 2 0 3 0 4 0 6 0 12 0 17-1 1 0 2-1 4-1 1 0 3-1 4-1 3 0 6-1 9-1 7-1 13-2 19-3 13-2 25-4 38-6 25-4 51-8 76-13 25-6 50-12 75-19 12-4 24-8 37-12 6-2 12-4 18-6 3-1 6-2 9-3 1-1 3-1 4-2 1 0 1 0 2 0 1-1 2-1 2-1 2-2 3-2 4-4 1-1 1-1 1-2 0-1 0-2 0-2 1-1 1-2 1-3 2-6 3-13 4-19 1-7 2-13 3-20 0-3 0-6 0-9 0-1 0-2 0-2 0-1 0-2 0-3 1-1 1-3 1-5 5-23 7-48 5-72-1-13-3-26-6-38-8-29 8 35 0 0z m-197 0c-2 4-3 9-5 13 0 1 0 1 0 2-1 0 0 1-1 1 0 1 0 2 0 2 0 1-1 2-1 3-1 2-3 4-4 5-2 2-5 4-7 4 2 2 4 3 7 5 1 1 2 2 3 2 1 1 2 1 2 2 0 1 0 1 0 2 1 0 1 1 2 1 0 1 1 2 1 4 0 2 0 4 0 6 0 3 0 5 0 7 0 3 0 5-1 7-1 6-4 10-8 14-1 2-3 3-5 4-3 2-5 4-8 5-3 1-6 2-9 3-3 0-5 0-7 0-3 0-6 0-8 0-13 0-25 0-37 0-5 0-10 0-14 0-1 0-2 0-3 0 0 0 0-4 0-5 0-3 0-6 0-9 0-1 0-2 0-3 0-1 0-1 1-1 1 0 12 0 12 0 0-8 0-16 0-24 0-13 0-25 0-38 0-4 0-7 0-11 0 0 0-1 0-1-3 0-5 0-8 0-1 0-2 0-4 0 0 0-1 0-1-1 0-2 0-4 0-6 0-1 0-14 0-14 10 0 19 0 29 0 5 0 11 0 16 0 1 0 3 0 4 0 0 0 0 3 0 3 0 6 0 11 0 17 0 1 0 1-1 1-1 0-2 0-4 0-1 0-3 0-4 0 0 0-1-1-1 0 0 5 0 10 0 15 0 2 0 5 0 8 0 1 0 1 0 2 0 0 0 0 1 0 2 0 5 0 8 0 2 0 4 0 6 0 1 0 3 0 4 0 1 0 2-1 3-2 1-1 2-2 3-3 0-1 0-1 0-2 0-2 1-3 1-4 1-1 1-2 2-3 0-1 0-1 0-1 0-1 0-2 0-2 1-6 2-12 3-17 1-3 1-5 2-8 0 0 0-1 0-1 0 0 0 0 0 0 11 0 21 0 32 0 0 0 1 0 1 0 0 0 0 0 0 0 0 3 0 5 0 8 0 5 0 10 0 15 0 0 0 0 0 0-1-2-1-4-2-5z m-26 53c0-2-3-3-4-4-1 0-1-1-1-1 0 0-1 0-1 0 0 0-1 0-1 0-1-1-1-2-2-2-1 0-2 0-3 0-2 0-4 0-5 0-1 0-2 0-2 0-3 0-7 0-10 0 0 0-4 0-4 0 0 9 0 19 0 28 0 0 13 0 14 0 4 0 8 0 12-1 1 0 3-1 4-2 1 0 2-1 3-2 1-2 2-4 3-6 0-1 0-1 0-2-1-1-1-1-1-2-1-1-1-1-1-2-1-1-1-2-1-4z m131-53c0 9 0 18 0 27 0 9-2 18-8 24-7 7-19 8-28 7-2 0-4 0-6-1-1 0-1-1-2-2-1 0-2 0-2-1-3-1-6-3-8-6 0 9 0 18 0 27 0 6 0 12 0 18 0 2 0 3 0 5 0 1 0 1 0 1-11 0-22 0-32 0-1 0-3 0-4 0 0 0 0-4 0-4 0-5 0-11 0-16 0 0 1 0 1 0 1 0 3 0 4 0 3 0 5 0 8 0 0 0 0-5 0-6 0-11 0-23 0-34 0-11 0-22 0-33 0-1 0-2 0-3 0-1 0-1-1-1-3 0-6 0-9 0-1 0-2 0-3 0 0 0 0-1 0-1 0-6 0-11 0-17 0-1 0-1 0-2 0 0 0 0 0 0 2 0 3 0 4 0 12 0 24 0 36 0 0 0 9 0 9 0 0 5 0 10 0 15 0 1 0 3 0 5 0 0-6 0-7 0 0 0-6 0-6 0 0 1 0 3 0 4 0 6 0 12 0 18 0 3 0 5 0 7 0 1 0 1 0 2 0 0 1 1 2 2 1 1 2 2 3 2 1 1 1 1 2 1 1 0 1 0 1 1 2 1 3 1 4 1 3 1 5 0 7-1 1-1 2-2 3-3 1-1 2-2 2-3 1-2 1-4 1-6 0-3 0-7 0-11 0-11 0-22 0-33 0-1 0-2 1-2 1 0 3 0 5 0 6 0 12 0 19 0 3 0 7 0 11 0 0 0 0 14 0 15 0 2 0 4 0 6-2-1-5-2-7-2z m7 122c-2 0-5 0-7 0-1 0-2 0-3 0 0 0 0 0 0 0-3-5-7-10-10-14-1-2-3-5-4-7 0 0-1-1-1-2 0 0 0-1 0-1 0-1 0-4 0-4 0 0 1 0 2 0 3 0 5 0 8 0 3 0 5 0 8 0 0 0 0-1 0-1 0-1 0-3 0-4 0-2 0-3 0-4 0-1 0-1 1-1 1 0 3 0 4 0 1 0 2 0 2 0 0 3 0 6 0 8 0 1 0 2 1 2 1 0 2 0 4 0 0 0 0 0 0 0 0 1 0 1 0 2 0 0 0 3 0 3-1 0-2 0-3 0-1 0-2 0-2 1 0 7 0 15 0 22z m-7-15c0-1 0-2 0-4 0-1 0-1 0-2 0 0 0-1 0-2 0 0-1 0-1 0-1 0-2 0-3 0-1 0-3 0-4 0 1 2 3 4 4 6 1 1 1 2 2 3 1 2 2 4 2 7 0-3 0-5 0-8z m41-2c-3 2-8 2-11 2-1 0-2 0-2 0 0 0 0 1 0 1 0 2 0 3 0 4 0 0 13 0 14 0 1 0 1 0 1 1 0 1 0 2 0 4 0 1 0 2 0 3 0 0-1 0-1 0-6 0-11 0-17 0-1 0-1 0-2 0 0 0 0-1 0-1-1-2-1-4-1-6-1-5-1-9-2-14 4 0 9 1 12-1 3-1 4-4 4-7-1-4-5-4-7-4-2 0-9-1-9 2-1-2-1-5-2-8 1 0 3-1 5-1 2-1 5-1 7-1 4 0 8 2 11 5 2 3 2 7 2 11 0 2 0 5 0 7 0 1-1 2-2 3 0 0 0 0 0 0-3 2 2 0 0 0z" horiz-adv-x="1000" />
90 92
91 93 <glyph glyph-name="up" unicode="&#xe832;" d="M687 254l-173 217c-8 9-22 9-29 0l-173-217c-9-12-1-29 15-29h345c16 0 24 17 15 29z" horiz-adv-x="1000" />
92 94
93 95 <glyph glyph-name="merge" unicode="&#xe833;" d="M200 110c0-72 58-131 130-131s130 59 130 131c0 45-24 86-60 109 18 139 133 179 202 190v-301c-38-23-65-64-65-112 0-72 59-130 130-130s130 58 130 130c0 48-26 89-65 112v487c39 23 65 64 65 112 0 72-58 130-130 130s-130-58-130-130c0-48 27-89 65-112v-55c-60-8-162-32-238-108-54-54-86-124-94-208-42-22-70-65-70-114z m468-158c-24 0-44 20-44 43s20 44 44 44c24 0 43-20 43-44s-19-43-43-43z m0 798c24 0 43-19 43-43s-20-43-43-43c-24 0-44 19-44 43s20 43 44 43z m-338-684c-24 0-43 20-43 43s19 44 43 44c24 0 43-20 43-44s-19-43-43-43z" horiz-adv-x="1000" />
94 96
95 97 <glyph glyph-name="spin-alt" unicode="&#xe834;" d="M498 850c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" />
96 98
97 99 <glyph glyph-name="spin" unicode="&#xe838;" d="M462 850c-6 0-11-5-11-11l0-183 0 0c0-6 5-11 11-11l69 0c1 0 1 0 1 0 7 0 12 5 12 11l0 183 0 0c0 6-5 11-12 11l-69 0c0 0 0 0-1 0z m250-47c-4 1-8-2-10-5l-91-158 0 0c-4-6-2-13 4-16l60-34c0-1 0-1 0-1 6-3 13-1 16 4l91 158c3 6 2 13-4 16l-61 35c-1 1-3 1-5 1z m-428-2c-2 0-4-1-6-2l-61-35c-5-3-7-10-4-16l91-157c0 0 0 0 0 0 3-6 10-8 16-5l61 35c5 4 7 11 4 16l-91 157c0 1 0 1 0 1-2 4-6 6-10 6z m620-163c-2 0-4 0-6-1l-157-91c0 0 0 0 0 0-6-3-8-10-5-16l35-61c4-5 11-7 16-4l157 91c1 0 1 0 1 0 6 3 7 11 4 16l-35 61c-2 4-6 6-10 5z m-810-4c-5 0-9-2-11-6l-35-61c-3-5-1-12 4-15l158-91 0 0c6-4 13-2 16 4l35 60c0 0 0 0 0 0 3 6 1 13-4 16l-158 91c-2 1-4 2-5 2z m712-235l0 0c-6 0-11-5-11-11l0-69c0-1 0-1 0-1 0-7 5-12 11-12l183 0 0 0c6 0 11 5 11 12l0 69c0 0 0 0 0 1 0 6-5 11-11 11l-183 0z m-794-5l0 0c-7 0-12-5-12-12l0-69c0 0 0 0 0-1 0-6 5-11 12-11l182 0 0 0c6 0 11 5 11 11l0 69c0 1 0 1 0 1 0 7-5 12-11 12l-182 0z m772-153c-4 0-8-2-10-6l-34-60c-1 0-1 0-1 0-3-6-1-13 4-16l158-91c6-3 13-1 16 4l35 61c3 5 1 12-4 15l-158 92 0 0c-2 1-4 1-6 1z m-566-5c-1 0-3 0-5-1l-157-91c0 0-1 0-1 0-5-3-7-10-4-16l35-61c3-5 10-7 16-4l157 91c0 0 0 0 0 0 6 3 8 10 5 16l-35 61c-3 3-7 6-11 5z m468-121c-2 0-4 0-6-1l-61-35c-5-4-7-11-4-16l91-157c0-1 0-1 0-1 3-6 11-7 16-4l61 35c5 3 7 10 4 16l-91 157c0 0 0 0 0 0-2 4-6 6-10 6z m-367-2c-4 0-8-2-10-6l-91-158c-3-6-1-13 4-16l61-35c5-3 12-1 15 4l92 158 0 0c3 6 1 13-5 16l-60 35c0 0 0 0 0 0-2 1-4 1-6 2z m149-58c-7 0-12-5-12-11l0-183 0 0c0-6 5-11 12-11l69 0c0 0 0 0 1 0 6 0 11 5 11 11l0 183 0 0c0 6-5 11-11 11l-69 0c-1 0-1 0-1 0z" horiz-adv-x="1000" />
98 100
99 101 <glyph glyph-name="docs" unicode="&#xf0c5;" d="M946 636q23 0 38-16t16-38v-678q0-23-16-38t-38-16h-535q-23 0-38 16t-16 38v160h-303q-23 0-38 16t-16 38v375q0 22 11 49t27 42l228 228q15 16 42 27t49 11h232q23 0 38-16t16-38v-183q38 23 71 23h232z m-303-119l-167-167h167v167z m-357 214l-167-167h167v167z m109-361l176 176v233h-214v-233q0-22-15-37t-38-16h-233v-357h286v143q0 22 11 49t27 42z m534-449v643h-215v-232q0-22-15-38t-38-15h-232v-358h500z" horiz-adv-x="1000" />
100 102
101 103 <glyph glyph-name="menu" unicode="&#xf0c9;" d="M857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-14-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
102 104
103 105 <glyph glyph-name="paste" unicode="&#xf0ea;" d="M429-79h500v358h-233q-22 0-37 15t-16 38v232h-214v-643z m142 804v36q0 7-5 12t-12 6h-393q-7 0-13-6t-5-12v-36q0-7 5-13t13-5h393q7 0 12 5t5 13z m143-375h167l-167 167v-167z m286-71v-375q0-23-16-38t-38-16h-535q-23 0-38 16t-16 38v89h-303q-23 0-38 16t-16 37v750q0 23 16 38t38 16h607q22 0 38-16t15-38v-183q12-7 20-15l228-228q16-15 27-42t11-49z" horiz-adv-x="1000" />
104 106
105 107 <glyph glyph-name="doc-text" unicode="&#xf0f6;" d="M819 638q16-16 27-42t11-50v-642q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h500q22 0 49-11t42-27z m-248 136v-210h210q-5 17-12 23l-175 175q-6 7-23 12z m215-853v572h-232q-23 0-38 16t-16 37v233h-429v-858h715z m-572 483q0 7 5 12t13 5h393q8 0 13-5t5-12v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36z m411-125q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36q0 8 5 13t13 5h393z m0-143q8 0 13-5t5-13v-36q0-8-5-13t-13-5h-393q-8 0-13 5t-5 13v36q0 8 5 13t13 5h393z" horiz-adv-x="857.1" />
106 108
107 109 <glyph glyph-name="plus-squared" unicode="&#xf0fe;" d="M714 314v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-25-10t-11-25v-72q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
108 110
109 111 <glyph glyph-name="folder-empty" unicode="&#xf114;" d="M857 118v393q0 22-15 38t-38 15h-393q-23 0-38 16t-16 38v36q0 22-15 38t-38 15h-179q-22 0-38-15t-16-38v-536q0-22 16-38t38-16h679q22 0 38 16t15 38z m72 393v-393q0-51-37-88t-88-37h-679q-51 0-88 37t-37 88v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h375q51 0 88-37t37-88z" horiz-adv-x="928.6" />
110 112
111 113 <glyph glyph-name="folder-open-empty" unicode="&#xf115;" d="M994 331q0 19-30 19h-607q-22 0-48-12t-39-29l-164-203q-11-13-11-22 0-20 30-20h607q23 0 48 13t40 29l164 203q10 12 10 22z m-637 90h429v90q0 22-16 38t-38 15h-321q-23 0-38 16t-16 38v36q0 22-15 38t-38 15h-179q-22 0-38-15t-16-38v-476l143 175q25 30 65 49t78 19z m708-90q0-35-25-67l-165-203q-24-30-65-49t-78-19h-607q-51 0-88 37t-37 88v536q0 51 37 88t88 37h179q51 0 88-37t37-88v-18h303q52 0 88-37t37-88v-90h107q30 0 56-13t37-40q8-17 8-37z" horiz-adv-x="1071.4" />
112 114
113 115 <glyph glyph-name="minus-squared" unicode="&#xf146;" d="M714 314v72q0 14-10 25t-25 10h-500q-15 0-25-10t-11-25v-72q0-14 11-25t25-10h500q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
114 116
115 117 <glyph glyph-name="minus-squared-alt" unicode="&#xf147;" d="M643 404v-36q0-8-5-13t-13-5h-464q-8 0-13 5t-5 13v36q0 7 5 12t13 5h464q8 0 13-5t5-12z m71-250v464q0 37-26 63t-63 26h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63z m72 464v-464q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h464q66 0 114-48t47-113z" horiz-adv-x="785.7" />
116 118
117 119 <glyph glyph-name="doc-inv" unicode="&#xf15b;" d="M571 564v264q13-8 21-16l227-228q8-7 16-20h-264z m-71-18q0-22 16-37t38-16h303v-589q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h446v-304z" horiz-adv-x="857.1" />
118 120
119 121 <glyph glyph-name="doc-text-inv" unicode="&#xf15c;" d="M819 584q8-7 16-20h-264v264q13-8 21-16z m-265-91h303v-589q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h446v-304q0-22 16-37t38-16z m89-411v36q0 8-5 13t-13 5h-393q-8 0-13-5t-5-13v-36q0-8 5-13t13-5h393q8 0 13 5t5 13z m0 143v36q0 8-5 13t-13 5h-393q-8 0-13-5t-5-13v-36q0-8 5-13t13-5h393q8 0 13 5t5 13z m0 143v36q0 7-5 12t-13 5h-393q-8 0-13-5t-5-12v-36q0-8 5-13t13-5h393q8 0 13 5t5 13z" horiz-adv-x="857.1" />
120 122
121 123 <glyph glyph-name="plus-squared-alt" unicode="&#xf196;" d="M643 404v-36q0-8-5-13t-13-5h-196v-196q0-8-5-13t-13-5h-36q-8 0-13 5t-5 13v196h-196q-8 0-13 5t-5 13v36q0 7 5 12t13 5h196v197q0 8 5 13t13 5h36q8 0 13-5t5-13v-197h196q8 0 13-5t5-12z m71-250v464q0 37-26 63t-63 26h-464q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63z m72 464v-464q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h464q66 0 114-48t47-113z" horiz-adv-x="785.7" />
122 124
123 125 <glyph glyph-name="file-code" unicode="&#xf1c9;" d="M819 638q16-16 27-42t11-50v-642q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h500q22 0 49-11t42-27z m-248 136v-210h210q-5 17-12 23l-175 175q-6 7-23 12z m215-853v572h-232q-23 0-38 16t-16 37v233h-429v-858h715z m-518 500q4 7 12 7t13-3l28-21q7-5 7-12t-3-13l-102-136 102-136q4-6 3-13t-7-12l-28-21q-6-4-13-4t-12 7l-126 168q-8 11 0 22z m447-167q8-11 0-22l-126-168q-4-6-11-7t-14 4l-28 21q-6 5-7 12t3 13l102 136-102 136q-4 6-3 13t7 12l28 21q6 4 14 3t11-7z m-346-258q-7 1-11 8t-3 13l77 464q1 7 7 11t14 3l35-5q7-2 11-8t3-13l-77-464q-1-7-7-11t-13-3z" horiz-adv-x="857.1" />
124 126
125 127 <glyph glyph-name="sliders" unicode="&#xf1de;" d="M196 64v-71h-196v71h196z m197 72q14 0 25-11t11-25v-143q0-14-11-25t-25-11h-143q-14 0-25 11t-11 25v143q0 15 11 25t25 11h143z m89 214v-71h-482v71h482z m-357 286v-72h-125v72h125z m732-572v-71h-411v71h411z m-536 643q15 0 26-10t10-26v-142q0-15-10-25t-26-11h-142q-15 0-25 11t-11 25v142q0 15 11 26t25 10h142z m358-286q14 0 25-10t10-25v-143q0-15-10-25t-25-11h-143q-15 0-25 11t-11 25v143q0 14 11 25t25 10h143z m178-71v-71h-125v71h125z m0 286v-72h-482v72h482z" horiz-adv-x="857.1" />
126 128
127 129 <glyph glyph-name="trash" unicode="&#xf1f8;" d="M286 82v393q0 8-5 13t-13 5h-36q-8 0-13-5t-5-13v-393q0-8 5-13t13-5h36q8 0 13 5t5 13z m143 0v393q0 8-5 13t-13 5h-36q-8 0-13-5t-5-13v-393q0-8 5-13t13-5h36q8 0 13 5t5 13z m142 0v393q0 8-5 13t-12 5h-36q-8 0-13-5t-5-13v-393q0-8 5-13t13-5h36q7 0 12 5t5 13z m-303 554h250l-27 65q-4 5-9 6h-177q-6-1-10-6z m518-18v-36q0-8-5-13t-13-5h-54v-529q0-46-26-80t-63-34h-464q-37 0-63 33t-27 79v531h-53q-8 0-13 5t-5 13v36q0 8 5 13t13 5h172l39 93q9 21 31 35t44 15h178q23 0 44-15t30-35l39-93h173q8 0 13-5t5-13z" horiz-adv-x="785.7" />
128 130 </font>
129 131 </defs>
130 132 </svg> No newline at end of file
1 NO CONTENT: modified file, binary diff hidden
1 NO CONTENT: modified file, binary diff hidden
1 NO CONTENT: modified file, binary diff hidden
@@ -1,82 +1,75 b''
1 1 /* COMMON */
2 2 var select2RefFilterResults = function(queryTerm, data) {
3 3 var filteredData = {results: []};
4 4 //filter results
5 5 $.each(data.results, function() {
6 6 var section = this.text;
7 7 var children = [];
8 8 $.each(this.children, function() {
9 9 if (queryTerm.length === 0 || this.text.toUpperCase().indexOf(queryTerm.toUpperCase()) >= 0) {
10 10 children.push(this);
11 11 }
12 12 });
13 13
14 14 if (children.length > 0) {
15 15 filteredData.results.push({
16 16 'text': section,
17 17 'children': children
18 18 });
19 19 }
20 20 });
21 21
22 22 return filteredData
23 23 };
24 24
25 25
26 26 var select2RefBaseSwitcher = function(targetElement, loadUrl, initialData){
27 27 var formatResult = function(result, container, query) {
28 28 return formatSelect2SelectionRefs(result);
29 29 };
30 30
31 31 var formatSelection = function(data, container) {
32 32 return formatSelect2SelectionRefs(data);
33 33 };
34 34
35 35 $(targetElement).select2({
36 36 cachedDataSource: {},
37 37 dropdownAutoWidth: true,
38 38 width: "resolve",
39 39 containerCssClass: "drop-menu",
40 40 dropdownCssClass: "drop-menu-dropdown",
41 41 query: function(query) {
42 42 var self = this;
43 43 var cacheKey = '__ALLREFS__';
44 44 var cachedData = self.cachedDataSource[cacheKey];
45 45 if (cachedData) {
46 46 var data = select2RefFilterResults(query.term, cachedData);
47 47 query.callback({results: data.results});
48 48 } else {
49 49 $.ajax({
50 50 url: loadUrl,
51 51 data: {},
52 52 dataType: 'json',
53 53 type: 'GET',
54 54 success: function(data) {
55 55 self.cachedDataSource[cacheKey] = data;
56 56 query.callback({results: data.results});
57 57 }
58 58 });
59 59 }
60 60 },
61 61 initSelection: function(element, callback) {
62 62 callback(initialData);
63 63 },
64 64 formatResult: formatResult,
65 65 formatSelection: formatSelection
66 66 });
67 67
68 68 };
69 69
70 70 /* WIDGETS */
71 71 var select2RefSwitcher = function(targetElement, initialData) {
72 72 var loadUrl = pyroutes.url('repo_refs_data',
73 73 {'repo_name': templateContext.repo_name});
74 74 select2RefBaseSwitcher(targetElement, loadUrl, initialData);
75 75 };
76
77 var select2FileHistorySwitcher = function(targetElement, initialData, state) {
78 var loadUrl = pyroutes.url('repo_file_history',
79 {'repo_name': templateContext.repo_name, 'commit_id': state.rev,
80 'f_path': state.f_path});
81 select2RefBaseSwitcher(targetElement, loadUrl, initialData);
82 };
@@ -1,39 +1,51 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2 <div class="table">
3 3
4 4 <table class="table rctable file_history">
5 5 %for cnt,cs in enumerate(c.pagination):
6 <tr id="chg_${cnt+1}" class="${'tablerow%s' % (cnt%2)}">
6 <tr id="chg_${cnt+1}" class="${('tablerow%s' % (cnt%2))}">
7 7 <td class="td-user">
8 8 ${base.gravatar_with_user(cs.author, 16)}
9 9 </td>
10 10 <td class="td-time">
11 11 <div class="date">
12 12 ${h.age_component(cs.date)}
13 13 </div>
14 14 </td>
15 15 <td class="td-message">
16 16 <div class="log-container">
17 17 <div class="message_history" title="${h.tooltip(cs.message)}">
18 18 <a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=cs.raw_id)}">
19 19 ${h.shorter(cs.message, 75)}
20 20 </a>
21 21 </div>
22 22 </div>
23 23 </td>
24 24 <td class="td-hash">
25 25 <code>
26 26 <a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=cs.raw_id)}">
27 27 <span>${h.show_id(cs)}</span>
28 28 </a>
29 29 </code>
30 30 </td>
31 31 <td class="td-actions">
32 32 <a href="${h.route_path('repo_files',repo_name=c.repo_name,commit_id=cs.raw_id,f_path=c.changelog_for_path)}">
33 33 ${_('Show File')}
34 34 </a>
35 35 </td>
36 <td class="td-actions">
37 <a href="${h.route_path('repo_compare',repo_name=c.repo_name, source_ref_type="rev", source_ref=cs.raw_id,target_ref_type="rev", target_ref=c.commit_id,_query=dict(merge='1',f_path=c.changelog_for_path))}">
38 ${_('Diff File')}
39 </a>
40 </td>
36 41 </tr>
37 42 %endfor
43 <tr>
44 <td colspan="6">
45 <a id="file_history_overview_full" href="${h.route_path('repo_changelog_file',repo_name=c.repo_name, commit_id=c.commit_id, f_path=c.f_path)}">
46 ${_('Show Full History')}
47 </a>
48 </td>
49 </tr>
38 50 </table>
39 51 </div>
@@ -1,40 +1,35 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2
3 3 % if c.authors:
4 4
5 5 <table class="sidebar-right-content">
6 6 % for email, user, commits in sorted(c.authors, key=lambda e: c.file_last_commit.author_email!=e[0]):
7 7 <tr class="file_author tooltip" title="${h.tooltip(h.author_string(email))}">
8 8
9 9 <td>
10 10 <span class="user commit-author">${h.link_to_user(user)}</span>
11 11 % if c.file_author:
12 12 <span class="commit-date">- ${h.age_component(c.file_last_commit.date)}</span>
13 <a href="#ShowAuthors" id="show_authors" class="action_link"> - ${_('Load All Authors')}</a>
13 14 % elif c.file_last_commit.author_email==email:
14 15 <span> (${_('last author')})</span>
15 16 % endif
16 17 </td>
17 18
18 19 <td>
19 20 % if not c.file_author:
20 21 <code>
21 22 % if commits == 1:
22 23 ${commits} ${_('Commit')}
23 24 % else:
24 25 ${commits} ${_('Commits')}
25 26 % endif
26 27 </code>
27 28 % endif
28 29 </td>
29 30 </tr>
30 <tr>
31 <td colspan="2">
32 % if c.file_author:
33 <a href="#ShowAuthors" id="show_authors" class="action_link">${_('Show Authors')}</a>
34 % endif
35 </td>
36 </tr>
31
37 32 % endfor
38 33 </table>
39 34 % endif
40 35
@@ -1,393 +1,463 b''
1 1 <%inherit file="/base/base.mako"/>
2 2
3 3 <%def name="title(*args)">
4 4 ${_('{} Files').format(c.repo_name)}
5 5 %if hasattr(c,'file'):
6 6 &middot; ${(h.safe_unicode(c.file.path) or '\\')}
7 7 %endif
8 8
9 9 %if c.rhodecode_name:
10 10 &middot; ${h.branding(c.rhodecode_name)}
11 11 %endif
12 12 </%def>
13 13
14 14 <%def name="breadcrumbs_links()">
15 15 ${_('Files')}
16 16 %if c.file:
17 17 @ ${h.show_id(c.commit)}
18 18 %endif
19 19 </%def>
20 20
21 21 <%def name="menu_bar_nav()">
22 22 ${self.menu_items(active='repositories')}
23 23 </%def>
24 24
25 25 <%def name="menu_bar_subnav()">
26 26 ${self.repo_menu(active='files')}
27 27 </%def>
28 28
29 29 <%def name="main()">
30 30 <div>
31 31 <div id="files_data">
32 32 <%include file='files_pjax.mako'/>
33 33 </div>
34 34 </div>
35 35 <script>
36 36
37 37 var metadataRequest = null;
38 38 var fileSourcePage = ${c.file_source_page};
39 39 var atRef = '${request.GET.get('at', '')}';
40 40
41 41 var getState = function(context) {
42 42 var url = $(location).attr('href');
43 43 var _base_url = '${h.route_path("repo_files",repo_name=c.repo_name,commit_id='',f_path='')}';
44 44 var _annotate_url = '${h.route_path("repo_files:annotated",repo_name=c.repo_name,commit_id='',f_path='')}';
45 45 _base_url = _base_url.replace('//', '/');
46 46 _annotate_url = _annotate_url.replace('//', '/');
47 47
48 48 //extract f_path from url.
49 49 var parts = url.split(_base_url);
50 50 if (parts.length != 2) {
51 51 parts = url.split(_annotate_url);
52 52 if (parts.length != 2) {
53 53 var rev = "tip";
54 54 var f_path = "";
55 55 } else {
56 56 var parts2 = parts[1].split('/');
57 57 var rev = parts2.shift(); // pop the first element which is the revision
58 58 var f_path = parts2.join('/');
59 59 }
60 60
61 61 } else {
62 62 var parts2 = parts[1].split('/');
63 63 var rev = parts2.shift(); // pop the first element which is the revision
64 64 var f_path = parts2.join('/');
65 65 }
66 66
67 67 var url_params = {
68 68 repo_name: templateContext.repo_name,
69 69 commit_id: rev,
70 70 f_path:'__FPATH__'
71 71 };
72 72 if (atRef !== '') {
73 73 url_params['at'] = atRef
74 74 }
75 75
76 76 var _url_base = pyroutes.url('repo_files', url_params);
77 77 var _node_list_url = pyroutes.url('repo_files_nodelist',
78 78 {repo_name: templateContext.repo_name,
79 79 commit_id: rev, f_path: f_path});
80 80
81 81 return {
82 82 url: url,
83 83 f_path: f_path,
84 84 rev: rev,
85 85 commit_id: "${c.commit.raw_id}",
86 86 node_list_url: _node_list_url,
87 87 url_base: _url_base
88 88 };
89 89 };
90 90
91 91 var getFilesMetadata = function() {
92 92 if (metadataRequest && metadataRequest.readyState != 4) {
93 93 metadataRequest.abort();
94 94 }
95 95 if (fileSourcePage) {
96 96 return false;
97 97 }
98 98
99 99 if ($('#file-tree-wrapper').hasClass('full-load')) {
100 100 // in case our HTML wrapper has full-load class we don't
101 101 // trigger the async load of metadata
102 102 return false;
103 103 }
104 104
105 105 var state = getState('metadata');
106 106 var url_data = {
107 107 'repo_name': templateContext.repo_name,
108 108 'commit_id': state.commit_id,
109 109 'f_path': state.f_path
110 110 };
111 111
112 112 var url = pyroutes.url('repo_nodetree_full', url_data);
113 113
114 114 metadataRequest = $.ajax({url: url});
115 115
116 116 metadataRequest.done(function(data) {
117 117 $('#file-tree').html(data);
118 118 timeagoActivate();
119 119 });
120 120 metadataRequest.fail(function (data, textStatus, errorThrown) {
121 console.log(data);
122 121 if (data.status != 0) {
123 122 alert("Error while fetching metadata.\nError code {0} ({1}).Please consider reloading the page".format(data.status,data.statusText));
124 123 }
125 124 });
126 125 };
127 126
128 var callbacks = function() {
129 timeagoActivate();
130
131 if ($('#trimmed_message_box').height() < 50) {
132 $('#message_expand').hide();
133 }
134
135 $('#message_expand').on('click', function(e) {
136 $('#trimmed_message_box').css('max-height', 'none');
137 $(this).hide();
138 });
139
127 var initFileJS = function () {
140 128 var state = getState('callbacks');
141 129
142 // VIEW FOR FILE SOURCE
143 if (fileSourcePage) {
144 // variants for with source code, not tree view
145
146 130 // select code link event
147 131 $("#hlcode").mouseup(getSelectionLink);
148 132
149 // file history select2 used for history, and switch to
133 // file history select2 used for history of file, and switch to
150 134 var initialCommitData = {
135 at_ref: atRef,
151 136 id: null,
152 text: '${_("Pick Commit")}',
137 text: '${c.commit.raw_id}',
153 138 type: 'sha',
154 raw_id: null,
155 files_url: null
139 raw_id: '${c.commit.raw_id}',
140 idx: ${c.commit.idx},
141 files_url: null,
156 142 };
157 143
158 select2FileHistorySwitcher('#diff1', initialCommitData, state);
144 // check if we have ref info.
145 var selectedRef = fileTreeRefs[atRef];
146 if (selectedRef !== undefined) {
147 $.extend(initialCommitData, selectedRef)
148 }
149
150 var loadUrl = pyroutes.url('repo_file_history', {'repo_name': templateContext.repo_name, 'commit_id': state.rev,'f_path': state.f_path});
151 var cacheKey = '__SINGLE_FILE_REFS__';
152 var cachedDataSource = {};
159 153
160 // show at, diff to actions handlers
161 $('#diff1').on('change', function(e) {
162 $('#diff_to_commit').removeClass('disabled').removeAttr("disabled");
163 $('#diff_to_commit').val(_gettext('Diff to Commit ') + e.val.truncateAfter(8, '...'));
154 var loadRefsData = function (query) {
155 $.ajax({
156 url: loadUrl,
157 data: {},
158 dataType: 'json',
159 type: 'GET',
160 success: function (data) {
161 cachedDataSource[cacheKey] = data;
162 query.callback({results: data.results});
163 }
164 });
165 };
164 166
165 $('#show_at_commit').removeClass('disabled').removeAttr("disabled");
166 $('#show_at_commit').val(_gettext('Show at Commit ') + e.val.truncateAfter(8, '...'));
167 var feedRefsData = function (query, cachedData) {
168 var data = {results: []};
169 //filter results
170 $.each(cachedData.results, function () {
171 var section = this.text;
172 var children = [];
173 $.each(this.children, function () {
174 if (query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
175 children.push(this)
176 }
177 });
178 data.results.push({
179 'text': section,
180 'children': children
181 })
167 182 });
168 183
169 $('#diff_to_commit').on('click', function(e) {
170 var diff1 = $('#diff1').val();
171 var diff2 = $('#diff2').val();
184 query.callback(data);
185 };
186
187 var select2FileHistorySwitcher = function (targetElement, loadUrl, initialData) {
188 var formatResult = function (result, container, query) {
189 return formatSelect2SelectionRefs(result);
190 };
191
192 var formatSelection = function (data, container) {
193 var commit_ref = data;
172 194
173 var url_data = {
174 repo_name: templateContext.repo_name,
175 source_ref: diff1,
176 source_ref_type: 'rev',
177 target_ref: diff2,
178 target_ref_type: 'rev',
179 merge: 1,
180 f_path: state.f_path
195 var tmpl = '';
196 if (commit_ref.type === 'sha') {
197 tmpl = (commit_ref.raw_id || "").substr(0,8);
198 } else if (commit_ref.type === 'branch') {
199 tmpl = tmpl.concat('<i class="icon-branch"></i> ');
200 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
201 } else if (commit_ref.type === 'tag') {
202 tmpl = tmpl.concat('<i class="icon-tag"></i> ');
203 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
204 } else if (commit_ref.type === 'book') {
205 tmpl = tmpl.concat('<i class="icon-bookmark"></i> ');
206 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
207 }
208 var idx = commit_ref.idx || 0;
209 tmpl = tmpl.concat('<span class="select-index-number">r{0}</span>'.format(idx));
210 return tmpl
181 211 };
182 window.location = pyroutes.url('repo_compare', url_data);
212
213 $(targetElement).select2({
214 dropdownAutoWidth: true,
215 width: "resolve",
216 containerCssClass: "drop-menu",
217 dropdownCssClass: "drop-menu-dropdown",
218 query: function(query) {
219 var cachedData = cachedDataSource[cacheKey];
220 if (cachedData) {
221 feedRefsData(query, cachedData)
222 } else {
223 loadRefsData(query)
224 }
225 },
226 initSelection: function(element, callback) {
227 callback(initialData);
228 },
229 formatResult: formatResult,
230 formatSelection: formatSelection
183 231 });
184 232
185 $('#show_at_commit').on('click', function(e) {
186 var diff1 = $('#diff1').val();
233 };
234
235 select2FileHistorySwitcher('#file_refs_filter', loadUrl, initialCommitData);
187 236
188 var annotate = $('#annotate').val();
189 if (annotate === "True") {
237 $('#file_refs_filter').on('change', function(e) {
238 var data = $('#file_refs_filter').select2('data');
239 var commit_id = data.id;
240
241 if ("${c.annotate}" === "True") {
190 242 var url = pyroutes.url('repo_files:annotated',
191 243 {'repo_name': templateContext.repo_name,
192 'commit_id': diff1, 'f_path': state.f_path});
244 'commit_id': commit_id, 'f_path': state.f_path});
193 245 } else {
194 246 var url = pyroutes.url('repo_files',
195 247 {'repo_name': templateContext.repo_name,
196 'commit_id': diff1, 'f_path': state.f_path});
248 'commit_id': commit_id, 'f_path': state.f_path});
197 249 }
198 250 window.location = url;
199 251
200 252 });
201 253
202 254 // show more authors
203 255 $('#show_authors').on('click', function(e) {
204 256 e.preventDefault();
205 257 var url = pyroutes.url('repo_file_authors',
206 258 {'repo_name': templateContext.repo_name,
207 259 'commit_id': state.rev, 'f_path': state.f_path});
208 260
209 261 $.pjax({
210 262 url: url,
211 263 data: 'annotate=${("1" if c.annotate else "0")}',
212 264 container: '#file_authors',
213 265 push: false,
214 266 timeout: 5000
215 267 }).complete(function(){
216 268 $('#show_authors').hide();
217 269 $('#file_authors_title').html(_gettext('All Authors'))
218 270 })
219 271 });
220 272
221 273 // load file short history
222 274 $('#file_history_overview').on('click', function(e) {
223 275 e.preventDefault();
224 276 path = state.f_path;
225 277 if (path.indexOf("#") >= 0) {
226 278 path = path.slice(0, path.indexOf("#"));
227 279 }
228 280 var url = pyroutes.url('repo_changelog_file',
229 281 {'repo_name': templateContext.repo_name,
230 282 'commit_id': state.rev, 'f_path': path, 'limit': 6});
231 283 $('#file_history_container').show();
232 284 $('#file_history_container').html('<div class="file-history-inner">{0}</div>'.format(_gettext('Loading ...')));
233 285
234 286 $.pjax({
235 287 url: url,
236 288 container: '#file_history_container',
237 289 push: false,
238 290 timeout: 5000
239 })
291 });
240 292 });
241 293
242 }
243 // VIEW FOR FILE TREE BROWSER
244 else {
294
295 };
296
297 var initTreeJS = function () {
298 var state = getState('callbacks');
245 299 getFilesMetadata();
246 300
247 301 // fuzzy file filter
248 302 fileBrowserListeners(state.node_list_url, state.url_base);
249 303
250 304 // switch to widget
251 305 var initialCommitData = {
252 306 at_ref: atRef,
253 307 id: null,
254 308 text: '${c.commit.raw_id}',
255 309 type: 'sha',
256 310 raw_id: '${c.commit.raw_id}',
257 311 idx: ${c.commit.idx},
258 312 files_url: null,
259 313 };
260 314
261 315 // check if we have ref info.
262 316 var selectedRef = fileTreeRefs[atRef];
263 317 if (selectedRef !== undefined) {
264 318 $.extend(initialCommitData, selectedRef)
265 319 }
266 320
267 321 var loadUrl = pyroutes.url('repo_refs_data', {'repo_name': templateContext.repo_name});
268 322 var cacheKey = '__ALL_FILE_REFS__';
269 323 var cachedDataSource = {};
270 324
271 325 var loadRefsData = function (query) {
272 326 $.ajax({
273 327 url: loadUrl,
274 328 data: {},
275 329 dataType: 'json',
276 330 type: 'GET',
277 331 success: function (data) {
278 332 cachedDataSource[cacheKey] = data;
279 333 query.callback({results: data.results});
280 334 }
281 335 });
282 336 };
283 337
284 338 var feedRefsData = function (query, cachedData) {
285 339 var data = {results: []};
286 340 //filter results
287 341 $.each(cachedData.results, function () {
288 342 var section = this.text;
289 343 var children = [];
290 344 $.each(this.children, function () {
291 345 if (query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
292 346 children.push(this)
293 347 }
294 348 });
295 349 data.results.push({
296 350 'text': section,
297 351 'children': children
298 352 })
299 353 });
300 354
301 355 //push the typed in commit idx
302 356 if (!isNaN(query.term)) {
303 357 var files_url = pyroutes.url('repo_files',
304 358 {'repo_name': templateContext.repo_name,
305 359 'commit_id': query.term, 'f_path': state.f_path});
306 360
307 361 data.results.push({
308 362 'text': _gettext('go to numeric commit'),
309 363 'children': [{
310 364 at_ref: null,
311 365 id: null,
312 366 text: 'r{0}'.format(query.term),
313 367 type: 'sha',
314 368 raw_id: query.term,
315 369 idx: query.term,
316 370 files_url: files_url,
317 371 }]
318 372 });
319 373 }
320 374 query.callback(data);
321 375 };
322 376
323 377 var select2RefFileSwitcher = function (targetElement, loadUrl, initialData) {
324 378 var formatResult = function (result, container, query) {
325 379 return formatSelect2SelectionRefs(result);
326 380 };
327 381
328 382 var formatSelection = function (data, container) {
329 383 var commit_ref = data;
330 384
331 385 var tmpl = '';
332 386 if (commit_ref.type === 'sha') {
333 tmpl = commit_ref.raw_id.substr(0,8);
387 tmpl = (commit_ref.raw_id || "").substr(0,8);
334 388 } else if (commit_ref.type === 'branch') {
335 389 tmpl = tmpl.concat('<i class="icon-branch"></i> ');
336 390 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
337 391 } else if (commit_ref.type === 'tag') {
338 392 tmpl = tmpl.concat('<i class="icon-tag"></i> ');
339 393 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
340 394 } else if (commit_ref.type === 'book') {
341 395 tmpl = tmpl.concat('<i class="icon-bookmark"></i> ');
342 396 tmpl = tmpl.concat(escapeHtml(commit_ref.text));
343 397 }
344 398
345 tmpl = tmpl.concat('<span class="select-index-number">r{0}</span>'.format(commit_ref.idx));
399 var idx = commit_ref.idx || 0;
400 tmpl = tmpl.concat('<span class="select-index-number">r{0}</span>'.format(idx));
346 401 return tmpl
347 402 };
348 403
349 404 $(targetElement).select2({
350 405 dropdownAutoWidth: true,
351 406 width: "resolve",
352 407 containerCssClass: "drop-menu",
353 408 dropdownCssClass: "drop-menu-dropdown",
354 409 query: function(query) {
355 410
356 411 var cachedData = cachedDataSource[cacheKey];
357 412 if (cachedData) {
358 413 feedRefsData(query, cachedData)
359 414 } else {
360 415 loadRefsData(query)
361 416 }
362 417 },
363 418 initSelection: function(element, callback) {
364 419 callback(initialData);
365 420 },
366 421 formatResult: formatResult,
367 422 formatSelection: formatSelection
368 423 });
369 424
370 425 };
371 426
372 427 select2RefFileSwitcher('#refs_filter', loadUrl, initialCommitData);
373 428
374 429 $('#refs_filter').on('change', function(e) {
375 430 var data = $('#refs_filter').select2('data');
376 431 window.location = data.files_url
377 432 });
378 433
379 }
380 434 };
381 435
382 436 $(document).ready(function() {
383 callbacks();
437 timeagoActivate();
438
439 if ($('#trimmed_message_box').height() < 50) {
440 $('#message_expand').hide();
441 }
442
443 $('#message_expand').on('click', function(e) {
444 $('#trimmed_message_box').css('max-height', 'none');
445 $(this).hide();
446 });
447
448 if (fileSourcePage) {
449 initFileJS()
450 } else {
451 initTreeJS()
452 }
453
384 454 var search_GET = "${request.GET.get('search','')}";
385 455 if (search_GET === "1") {
386 456 NodeFilter.initFilter();
387 457 NodeFilter.focus();
388 458 }
389 459 });
390 460
391 461 </script>
392 462
393 463 </%def> No newline at end of file
@@ -1,53 +1,64 b''
1 1
2 2 <div id="codeblock" class="browserblock">
3 3 <div class="browser-header">
4 4 <div class="browser-nav">
5 5
6 6 <div class="info_box">
7 7
8 8 <div class="info_box_elem previous">
9 9 <a id="prev_commit_link" data-commit-id="${c.prev_commit.raw_id}" class=" ${('disabled' if c.url_prev == '#' else '')}" href="${c.url_prev}" title="${_('Previous commit')}"><i class="icon-left"></i></a>
10 10 </div>
11 11
12 12 ${h.hidden('refs_filter')}
13 13
14 14 <div class="info_box_elem next">
15 15 <a id="next_commit_link" data-commit-id="${c.next_commit.raw_id}" class=" ${('disabled' if c.url_next == '#' else '')}" href="${c.url_next}" title="${_('Next commit')}"><i class="icon-right"></i></a>
16 16 </div>
17 17 </div>
18 18
19 19 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
20 <div title="${_('Add New File')}" class="btn btn-primary new-file">
21 <a href="${h.route_path('repo_files_add_file',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path, _anchor='edit')}">
22 ${_('Add File')}</a>
20 <div>
21 <a class="btn btn-primary new-file" href="${h.route_path('repo_files_add_file',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path, _anchor='edit')}">
22 ${_('Upload File')}
23 </a>
24 <a class="btn btn-primary new-file" href="${h.route_path('repo_files_add_file',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path, _anchor='edit')}">
25 ${_('Add File')}
26 </a>
23 27 </div>
24 28 % endif
25 29
26 30 % if c.enable_downloads:
27 31 <% at_path = '{}'.format(request.GET.get('at') or c.commit.raw_id[:6]) %>
28 32 <div class="btn btn-default new-file">
33 % if c.f_path == '/':
29 34 <a href="${h.route_path('repo_archivefile',repo_name=c.repo_name, fname='{}.zip'.format(c.commit.raw_id))}">
30 ${_('Download ZIP @ ')} <code>${at_path}</code>
35 ${_('Download full tree ZIP')}
31 36 </a>
37 % else:
38 <a href="${h.route_path('repo_archivefile',repo_name=c.repo_name, fname='{}.zip'.format(c.commit.raw_id))}">
39 ${_('Download this tree ZIP')}
40 </a>
41 % endif
32 42 </div>
33 43 % endif
34 44
35 45 <div class="files-quick-filter">
36 46 <ul class="files-filter-box">
37 47 <li class="files-filter-box-path">
38 48 <i class="icon-search"></i>
39 49 </li>
40 50 <li class="files-filter-box-input">
41 51 <input onkeydown="NodeFilter.initFilter(event)" class="init" type="text" placeholder="Quick filter" name="filter" size="25" id="node_filter" autocomplete="off">
42 52 </li>
43 53 </ul>
44 54 </div>
45 55 </div>
46 56
47 57 </div>
58
48 59 ## file tree is computed from caches, and filled in
49 60 <div id="file-tree">
50 61 ${c.file_tree |n}
51 62 </div>
52 63
53 64 </div>
@@ -1,89 +1,83 b''
1 1 <%
2 2 if request.GET.get('at'):
3 3 query={'at': request.GET.get('at')}
4 4 else:
5 5 query=None
6 6 %>
7 7 <div id="file-tree-wrapper" class="browser-body ${('full-load' if c.full_load else '')}">
8 8 <table class="code-browser rctable repo_summary">
9 9 <thead>
10 10 <tr>
11 11 <th>${_('Name')}</th>
12 12 <th>${_('Size')}</th>
13 13 <th>${_('Modified')}</th>
14 14 <th>${_('Last Commit')}</th>
15 15 <th>${_('Author')}</th>
16 16 </tr>
17 17 </thead>
18 18
19 19 <tbody id="tbody">
20 %if c.file.parent:
21 <tr class="parity0">
22 <td class="td-componentname">
23 <a href="${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.file.parent.path, _query=query)}">
24 <i class="icon-directory"></i>..
25 </a>
20 <tr>
21 <td colspan="5">
22
23 ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.file.path, request.GET.get('at'), limit_items=True)}
24
26 25 </td>
27 <td></td>
28 <td></td>
29 <td></td>
30 <td></td>
31 26 </tr>
32 %endif
33 27 %for cnt,node in enumerate(c.file):
34 28 <tr class="parity${cnt%2}">
35 29 <td class="td-componentname">
36 30 % if node.is_submodule():
37 31 <span class="submodule-dir">
38 32 % if node.url.startswith('http://') or node.url.startswith('https://'):
39 33 <a href="${node.url}">
40 34 <i class="icon-directory browser-dir"></i>${node.name}
41 35 </a>
42 36 % else:
43 37 <i class="icon-directory browser-dir"></i>${node.name}
44 38 % endif
45 39 </span>
46 40 % else:
47 41
48 42 <a href="${h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=h.safe_unicode(node.path), _query=query)}">
49 43 <i class="${('icon-file-text browser-file' if node.is_file() else 'icon-directory browser-dir')}"></i>${node.name}
50 44 </a>
51 45 % endif
52 46 </td>
53 47 %if node.is_file():
54 48 <td class="td-size" data-attr-name="size">
55 49 % if c.full_load:
56 50 <span data-size="${node.size}">${h.format_byte_size_binary(node.size)}</span>
57 51 % else:
58 52 ${_('Loading ...')}
59 53 % endif
60 54 </td>
61 55 <td class="td-time" data-attr-name="modified_at">
62 56 % if c.full_load:
63 57 <span data-date="${node.last_commit.date}">${h.age_component(node.last_commit.date)}</span>
64 58 % endif
65 59 </td>
66 60 <td class="td-hash" data-attr-name="commit_id">
67 61 % if c.full_load:
68 62 <div class="tooltip" title="${h.tooltip(node.last_commit.message)}">
69 63 <pre data-commit-id="${node.last_commit.raw_id}">r${node.last_commit.idx}:${node.last_commit.short_id}</pre>
70 64 </div>
71 65 % endif
72 66 </td>
73 67 <td class="td-user" data-attr-name="author">
74 68 % if c.full_load:
75 69 <span data-author="${node.last_commit.author}" title="${h.tooltip(node.last_commit.author)}">${h.gravatar_with_user(request, node.last_commit.author)|n}</span>
76 70 % endif
77 71 </td>
78 72 %else:
79 73 <td></td>
80 74 <td></td>
81 75 <td></td>
82 76 <td></td>
83 77 %endif
84 78 </tr>
85 79 %endfor
86 80 </tbody>
87 81 <tbody id="tbody_filtered"></tbody>
88 82 </table>
89 83 </div>
@@ -1,41 +1,34 b''
1 1 <%def name="title(*args)">
2 2 ${_('{} Files').format(c.repo_name)}
3 3 %if hasattr(c,'file'):
4 4 &middot; ${(h.safe_unicode(c.file.path) or '\\')}
5 5 %endif
6 6
7 7 %if c.rhodecode_name:
8 8 &middot; ${h.branding(c.rhodecode_name)}
9 9 %endif
10 10 </%def>
11 11
12 12 <div>
13 13
14 14 <div class="summary-detail">
15 15 <div class="summary-detail-header">
16 <div class="breadcrumbs files_location">
17 <h4>
18 ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.file.path, request.GET.get('at'))}
19 %if c.annotate:
20 - ${_('annotation')}
21 %endif
22 </h4>
23 </div>
16
24 17 </div><!--end summary-detail-header-->
25 18
26 19 % if c.file.is_submodule():
27 20 <span class="submodule-dir">Submodule ${h.escape(c.file.name)}</span>
28 21 % elif c.file.is_dir():
29 22 <%include file='files_tree_header.mako'/>
30 23 % else:
31 24 <%include file='files_source_header.mako'/>
32 25 % endif
33 26
34 27 </div> <!--end summary-detail-->
35 28 % if c.file.is_dir():
36 29 <%include file='files_browser.mako'/>
37 30 % else:
38 31 <%include file='files_source.mako'/>
39 32 % endif
40 33
41 34 </div>
@@ -1,131 +1,148 b''
1 1 <%namespace name="sourceblock" file="/codeblocks/source.mako"/>
2 2
3 <div id="codeblock" class="codeblock">
4 <div class="codeblock-header">
3 <div id="codeblock" class="browserblock">
4 <div class="browser-header">
5 <div class="browser-nav">
6 <div class="pull-left">
7 ## loads the history for a file
8 ${h.hidden('file_refs_filter')}
9 </div>
10
11 <div class="pull-right">
12
13 ## Download
14 % if c.lf_node:
15 <a class="btn btn-default" href="${h.route_path('repo_file_download',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path, _query=dict(lf=1))}">
16 ${_('Download largefile')}
17 </a>
18 % else:
19 <a class="btn btn-default" href="${h.route_path('repo_file_download',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}">
20 ${_('Download file')}
21 </a>
22 % endif
23
24 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
25 ## on branch head, can edit files
26 %if c.on_branch_head and c.branch_or_raw_id and not c.file.is_binary:
27 ## binary files are delete only
28 % if c.file.is_binary:
29 ${h.link_to(_('Edit'), '#Edit', class_="btn btn-default disabled tooltip", title=_('Editing binary files not allowed'))}
30 ${h.link_to(_('Delete'), h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _anchor='edit'),class_="btn btn-danger")}
31 % else:
32 <a class="btn btn-default" href="${h.route_path('repo_files_edit_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _anchor='edit')}">
33 ${_('Edit on branch: ')}<code>${c.branch_name}</code>
34 </a>
35
36 <a class="btn btn-danger" href="${h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _anchor='edit')}">
37 ${_('Delete')}
38 </a>
39 % endif
40 ## not on head, forbid all
41 % else:
42 ${h.link_to(_('Edit'), '#Edit', class_="btn btn-default disabled tooltip", title=_('Editing files allowed only when on branch head commit'))}
43 ${h.link_to(_('Delete'), '#Delete', class_="btn btn-default btn-danger disabled tooltip", title=_('Deleting files allowed only when on branch head commit'))}
44 % endif
45 %endif
46
47 </div>
48 </div>
49 <div id="file_history_container"></div>
50
51 </div>
52 </div>
53
54 <div class="codeblock codeblock-header">
55 <div>
56 ${h.files_breadcrumbs(c.repo_name,c.commit.raw_id,c.file.path, request.GET.get('at'))}
57 </div>
5 58 <div class="stats">
6 <span class="stats-filename">
7 <strong>
8 <i class="icon-file-text"></i>
9 ${c.file.unicode_path_safe}
10 </strong>
11 </span>
12 <span class="item last"><i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${c.f_path}" title="${_('Copy the full path')}"></i></span>
13 <br/>
14 59
15 60 % if c.lf_node:
16 61 <span title="${_('This file is a pointer to large binary file')}"> | ${_('LargeFile')} ${h.format_byte_size_binary(c.lf_node.size)} </span>
17 62 % endif
18 63
19 64 <div class="stats-info">
20 65 <span class="stats-first-item">${c.file.lines()[0]} ${_ungettext('line', 'lines', c.file.lines()[0])}</span>
21 66 <span> | ${h.format_byte_size_binary(c.file.size)}</span>
22 67 <span> | ${c.file.mimetype} </span>
23 68 <span> | ${h.get_lexer_for_filenode(c.file).__class__.__name__}</span>
24 69 </div>
70
25 71 </div>
26 <div class="buttons">
27 <a id="file_history_overview" href="#">
72 <div class="pull-right">
73 <a id="file_history_overview" href="#loadHistory">
28 74 ${_('History')}
29 75 </a>
30 <a id="file_history_overview_full" style="display: none" href="${h.route_path('repo_changelog_file',repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path)}">
31 ${_('Show Full History')}
32 </a> |
76 |
33 77 %if c.annotate:
34 78 ${h.link_to(_('Source'), h.route_path('repo_files', repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
35 79 %else:
36 80 ${h.link_to(_('Annotation'), h.route_path('repo_files:annotated',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
37 81 %endif
38 82 | ${h.link_to(_('Raw'), h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
39 |
40 % if c.lf_node:
41 <a href="${h.route_path('repo_file_download',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path, _query=dict(lf=1))}">
42 ${_('Download largefile')}
43 </a>
44 % else:
45 <a href="${h.route_path('repo_file_download',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path)}">
46 ${_('Download')}
47 </a>
48 % endif
49 83
50 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
51 |
52 %if c.on_branch_head and c.branch_or_raw_id and not c.file.is_binary:
53 <a href="${h.route_path('repo_files_edit_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _anchor='edit')}">
54 ${_('Edit on Branch:{}').format(c.branch_name)}
55 </a>
56 | <a class="btn-danger btn-link" href="${h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _anchor='edit')}">${_('Delete')}
57 </a>
58 %elif c.on_branch_head and c.branch_or_raw_id and c.file.is_binary:
59 ${h.link_to(_('Edit'), '#', class_="btn btn-link disabled tooltip", title=_('Editing binary files not allowed'))}
60 | ${h.link_to(_('Delete'), h.route_path('repo_files_remove_file',repo_name=c.repo_name,commit_id=c.branch_or_raw_id,f_path=c.f_path, _anchor='edit'),class_="btn-danger btn-link")}
61 %else:
62 ${h.link_to(_('Edit'), '#', class_="btn btn-link disabled tooltip", title=_('Editing files allowed only when on branch head commit'))}
63 | ${h.link_to(_('Delete'), '#', class_="btn btn-danger btn-link disabled tooltip", title=_('Deleting files allowed only when on branch head commit'))}
64 %endif
65 %endif
66 84 </div>
67 </div>
68 <div id="file_history_container"></div>
85
69 86 <div class="code-body">
70 87 %if c.file.is_binary:
71 88 <% rendered_binary = h.render_binary(c.repo_name, c.file)%>
72 89 % if rendered_binary:
73 90 ${rendered_binary}
74 91 % else:
75 92 <div>
76 93 ${_('Binary file (%s)') % c.file.mimetype}
77 94 </div>
78 95 % endif
79 96 %else:
80 97 % if c.file.size < c.visual.cut_off_limit_file:
81 98 %if c.renderer and not c.annotate:
82 99 ## pick relative url based on renderer
83 100 <%
84 101 relative_urls = {
85 102 'raw': h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path),
86 103 'standard': h.route_path('repo_files',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path),
87 104 }
88 105 %>
89 106 ${h.render(c.file.content, renderer=c.renderer, relative_urls=relative_urls)}
90 107 %else:
91 108 <table class="cb codehilite">
92 109 %if c.annotate:
93 110 <% color_hasher = h.color_hasher() %>
94 111 %for annotation, lines in c.annotated_lines:
95 112 ${sourceblock.render_annotation_lines(annotation, lines, color_hasher)}
96 113 %endfor
97 114 %else:
98 115 %for line_num, tokens in enumerate(c.lines, 1):
99 116 ${sourceblock.render_line(line_num, tokens)}
100 117 %endfor
101 118 %endif
102 119 </table>
103 120 %endif
104 121 %else:
105 122 ${_('File size {} is bigger then allowed limit {}. ').format(h.format_byte_size_binary(c.file.size), h.format_byte_size_binary(c.visual.cut_off_limit_file))} ${h.link_to(_('Show as raw'),
106 123 h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
107 124 %endif
108 125 %endif
109 126 </div>
110 127 </div>
111 128
112 129 <script type="text/javascript">
113 130 % if request.GET.get('mark'):
114 131
115 132 $(function(){
116 133 $(".codehilite").mark(
117 134 "${request.GET.get('mark')}",
118 135 {
119 136 "className": 'match',
120 137 "accuracy": "complementary",
121 138 "ignorePunctuation": ":._(){}[]!'+=".split(""),
122 139 "each": function(el) {
123 140 // and also highlight lines !
124 141 $($(el).closest('tr')).find('td.cb-lineno').addClass('cb-line-selected');
125 142 }
126 143 }
127 144 );
128 145
129 146 });
130 147 % endif
131 148 </script>
@@ -1,84 +1,61 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2 <%namespace name="file_base" file="/files/base.mako"/>
3 3
4 4 <div class="summary">
5 5 <div class="fieldset">
6 6 <div class="left-content">
7 7
8 8 <div class="left-content-avatar">
9 9 ${base.gravatar(c.file_last_commit.author_email, 30)}
10 10 </div>
11 11
12 12 <div class="left-content-message">
13 13 <div class="fieldset collapsable-content no-hide" data-toggle="summary-details">
14 14 <div class="commit truncate-wrap">${h.urlify_commit_message(h.chop_at_smart(c.commit.message, '\n', suffix_if_chopped='...'), c.repo_name)}</div>
15 15 </div>
16 16
17 17 <div class="fieldset collapsable-content" data-toggle="summary-details">
18 18 <div class="commit">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div>
19 19 </div>
20 20
21 21 <div class="fieldset" data-toggle="summary-details">
22 22 <div class="" id="file_authors">
23 23 ## loads single author, or ALL
24 24 <%include file='file_authors_box.mako'/>
25 25 </div>
26 26 </div>
27 27 </div>
28 28
29 29 <div class="fieldset collapsable-content" data-toggle="summary-details">
30 30 <div class="left-label-summary-files">
31 31 <p>${_('File last commit')}</p>
32 32 <div class="right-label-summary">
33 33 <code><a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.file_last_commit.raw_id)}">${h.show_id(c.file_last_commit)}</a></code>
34 34
35 35 ${file_base.refs(c.file_last_commit)}
36 36 </div>
37 37 </div>
38 38 </div>
39
40
41 <div class="fieldset collapsable-content" data-toggle="summary-details">
42 <div class="left-label-summary-files">
43 <p class="spacing">${_('Show/Diff file')}</p>
44 <div class="right-label-summary">
45 ${h.hidden('diff1')}
46 ${h.hidden('diff2',c.commit.raw_id)}
47 ${h.hidden('annotate', c.annotate)}
48 </div>
49 </div>
50 </div>
51
52
53 <div class="fieldset collapsable-content" data-toggle="summary-details">
54 <div class="left-label-summary-files">
55 <p>${_('Action')}</p>
56 <div class="right-label-summary">
57 ${h.submit('diff_to_commit',_('Diff to Commit'),class_="btn disabled",disabled="true")}
58 ${h.submit('show_at_commit',_('Show at Commit'),class_="btn disabled",disabled="true")}
59 </div>
60 </div>
61 </div>
62 39 </div>
63 40
64 41 <div class="right-content">
65 42 <div data-toggle="summary-details">
66 43 <div class="tags commit-info tags-main">
67 44 <code><a href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=c.commit.raw_id)}">${h.show_id(c.commit)}</a></code>
68 45 ${file_base.refs(c.commit)}
69 46 </div>
70 47 </div>
71 48 </div>
72 49
73 50 <div class="clear-fix"></div>
74 51
75 52 <div class="btn-collapse" data-toggle="summary-details">
76 53 ${_('Show More')}
77 54 </div>
78 55
79 56 </div>
80 57 </div>
81 58
82 59 <script>
83 60 collapsableContent();
84 61 </script>
General Comments 0
You need to be logged in to leave comments. Login now