##// END OF EJS Templates
templates: pass in request where possible to avoid threadglobals
super-admin -
r5045:0ea2e860 default
parent child Browse files
Show More
@@ -1,1262 +1,1262 b''
1 1
2 2 <%!
3 3 from rhodecode.lib import html_filters
4 4 %>
5 5
6 6 <%inherit file="root.mako"/>
7 7
8 8 <%include file="/ejs_templates/templates.html"/>
9 9
10 10 <div class="outerwrapper">
11 11 <!-- HEADER -->
12 12 <div class="header">
13 13 <div id="header-inner" class="wrapper">
14 14 <div id="logo">
15 15 <div class="logo-wrapper">
16 16 <a href="${h.route_path('home')}"><img src="${h.asset('images/rhodecode-logo-white-60x60.png')}" alt="RhodeCode"/></a>
17 17 </div>
18 18 % if c.rhodecode_name:
19 19 <div class="branding">
20 20 <a href="${h.route_path('home')}">${h.branding(c.rhodecode_name)}</a>
21 21 </div>
22 22 % endif
23 23 </div>
24 24 <!-- MENU BAR NAV -->
25 25 ${self.menu_bar_nav()}
26 26 <!-- END MENU BAR NAV -->
27 27 </div>
28 28 </div>
29 29 ${self.menu_bar_subnav()}
30 30 <!-- END HEADER -->
31 31
32 32 <!-- CONTENT -->
33 33 <div id="content" class="wrapper">
34 34
35 35 <rhodecode-toast id="notifications"></rhodecode-toast>
36 36
37 37 <div class="main">
38 38 ${next.main()}
39 39 </div>
40 40
41 41 </div>
42 42 <!-- END CONTENT -->
43 43
44 44 </div>
45 45
46 46 <!-- FOOTER -->
47 47 <div id="footer">
48 48 <div id="footer-inner" class="title wrapper">
49 49 <div>
50 50 <% sid = 'block' if request.GET.get('showrcid') else 'none' %>
51 51
52 52 <p class="footer-link-right">
53 53 <a class="grey-link-action" href="${h.route_path('home', _query={'showrcid': 1})}">
54 54 RhodeCode
55 55 % if c.visual.show_version:
56 56 ${c.rhodecode_version}
57 57 % endif
58 58 ${c.rhodecode_edition}
59 59 </a> |
60 60
61 61 % if c.visual.rhodecode_support_url:
62 62 <a class="grey-link-action" href="${c.visual.rhodecode_support_url}" target="_blank">${_('Support')}</a> |
63 63 <a class="grey-link-action" href="https://docs.rhodecode.com" target="_blank">${_('Documentation')}</a>
64 64 % endif
65 65
66 66 </p>
67 67
68 68 <p class="server-instance" style="display:${sid}">
69 69 ## display hidden instance ID if specially defined
70 70 &copy; 2010-${h.datetime.today().year}, <a href="${h.route_url('rhodecode_official')}" target="_blank">RhodeCode GmbH</a>. All rights reserved.
71 71 % if c.rhodecode_instanceid:
72 72 ${_('RhodeCode instance id: {}').format(c.rhodecode_instanceid)}
73 73 % endif
74 74 </p>
75 75 </div>
76 76 </div>
77 77 </div>
78 78
79 79 <!-- END FOOTER -->
80 80
81 81 ### MAKO DEFS ###
82 82
83 83 <%def name="menu_bar_subnav()">
84 84 </%def>
85 85
86 86 <%def name="breadcrumbs(class_='breadcrumbs')">
87 87 <div class="${class_}">
88 88 ${self.breadcrumbs_links()}
89 89 </div>
90 90 </%def>
91 91
92 92 <%def name="admin_menu(active=None)">
93 93
94 94 <div id="context-bar">
95 95 <div class="wrapper">
96 96 <div class="title">
97 97 <div class="title-content">
98 98 <div class="title-main">
99 99 % if c.is_super_admin:
100 100 ${_('Super-admin Panel')}
101 101 % else:
102 102 ${_('Delegated Admin Panel')}
103 103 % endif
104 104 </div>
105 105 </div>
106 106 </div>
107 107
108 108 <ul id="context-pages" class="navigation horizontal-list">
109 109
110 110 ## super-admin case
111 111 % if c.is_super_admin:
112 112 <li class="${h.is_active('audit_logs', active)}"><a href="${h.route_path('admin_audit_logs')}">${_('Admin audit logs')}</a></li>
113 113 <li class="${h.is_active('repositories', active)}"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
114 114 <li class="${h.is_active('repository_groups', active)}"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
115 115 <li class="${h.is_active('users', active)}"><a href="${h.route_path('users')}">${_('Users')}</a></li>
116 116 <li class="${h.is_active('user_groups', active)}"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
117 117 <li class="${h.is_active('artifacts', active)}"><a href="${h.route_path('admin_artifacts')}">${_('Artifacts')}</a></li>
118 118 <li class="${h.is_active('permissions', active)}"><a href="${h.route_path('admin_permissions_application')}">${_('Permissions')}</a></li>
119 119 <li class="${h.is_active('authentication', active)}"><a href="${h.route_path('auth_home', traverse='')}">${_('Authentication')}</a></li>
120 120 <li class="${h.is_active('integrations', active)}"><a href="${h.route_path('global_integrations_home')}">${_('Integrations')}</a></li>
121 121 <li class="${h.is_active('defaults', active)}"><a href="${h.route_path('admin_defaults_repositories')}">${_('Defaults')}</a></li>
122 122 <li class="${h.is_active('settings', active)}"><a href="${h.route_path('admin_settings')}">${_('Settings')}</a></li>
123 123
124 124 ## delegated admin
125 125 % elif c.is_delegated_admin:
126 126 <%
127 127 repositories=c.auth_user.repositories_admin or c.can_create_repo
128 128 repository_groups=c.auth_user.repository_groups_admin or c.can_create_repo_group
129 129 user_groups=c.auth_user.user_groups_admin or c.can_create_user_group
130 130 %>
131 131
132 132 %if repositories:
133 133 <li class="${h.is_active('repositories', active)} local-admin-repos"><a href="${h.route_path('repos')}">${_('Repositories')}</a></li>
134 134 %endif
135 135 %if repository_groups:
136 136 <li class="${h.is_active('repository_groups', active)} local-admin-repo-groups"><a href="${h.route_path('repo_groups')}">${_('Repository groups')}</a></li>
137 137 %endif
138 138 %if user_groups:
139 139 <li class="${h.is_active('user_groups', active)} local-admin-user-groups"><a href="${h.route_path('user_groups')}">${_('User groups')}</a></li>
140 140 %endif
141 141 % endif
142 142 </ul>
143 143
144 144 </div>
145 145 <div class="clear"></div>
146 146 </div>
147 147 </%def>
148 148
149 149 <%def name="dt_info_panel(elements)">
150 150 <dl class="dl-horizontal">
151 151 %for dt, dd, title, show_items in elements:
152 152 <dt>${dt}:</dt>
153 153 <dd title="${h.tooltip(title)}">
154 154 %if callable(dd):
155 155 ## allow lazy evaluation of elements
156 156 ${dd()}
157 157 %else:
158 158 ${dd}
159 159 %endif
160 160 %if show_items:
161 161 <span class="btn-collapse" data-toggle="item-${h.md5_safe(dt)[:6]}-details">${_('Show More')} </span>
162 162 %endif
163 163 </dd>
164 164
165 165 %if show_items:
166 166 <div class="collapsable-content" data-toggle="item-${h.md5_safe(dt)[:6]}-details" style="display: none">
167 167 %for item in show_items:
168 168 <dt></dt>
169 169 <dd>${item}</dd>
170 170 %endfor
171 171 </div>
172 172 %endif
173 173
174 174 %endfor
175 175 </dl>
176 176 </%def>
177 177
178 178 <%def name="tr_info_entry(element)">
179 179 <% key, val, title, show_items = element %>
180 180
181 181 <tr>
182 182 <td style="vertical-align: top">${key}</td>
183 183 <td title="${h.tooltip(title)}">
184 184 %if callable(val):
185 185 ## allow lazy evaluation of elements
186 186 ${val()}
187 187 %else:
188 188 ${val}
189 189 %endif
190 190 %if show_items:
191 191 <div class="collapsable-content" data-toggle="item-${h.md5_safe(h.safe_str(val))[:6]}-details" style="display: none">
192 192 % for item in show_items:
193 193 <dt></dt>
194 194 <dd>${item}</dd>
195 195 % endfor
196 196 </div>
197 197 %endif
198 198 </td>
199 199 <td style="vertical-align: top">
200 200 %if show_items:
201 201 <span class="btn-collapse" data-toggle="item-${h.md5_safe(h.safe_str(val))[:6]}-details">${_('Show More')} </span>
202 202 %endif
203 203 </td>
204 204 </tr>
205 205
206 206 </%def>
207 207
208 208 <%def name="gravatar(email, size=16, tooltip=False, tooltip_alt=None, user=None, extra_class=None)">
209 209 <%
210 210 if size > 16:
211 211 gravatar_class = ['gravatar','gravatar-large']
212 212 else:
213 213 gravatar_class = ['gravatar']
214 214
215 215 data_hovercard_url = ''
216 216 data_hovercard_alt = tooltip_alt.replace('<', '&lt;').replace('>', '&gt;') if tooltip_alt else ''
217 217
218 218 if tooltip:
219 219 gravatar_class += ['tooltip-hovercard']
220 220 if extra_class:
221 221 gravatar_class += extra_class
222 222 if tooltip and user:
223 223 if user.username == h.DEFAULT_USER:
224 224 gravatar_class.pop(-1)
225 225 else:
226 226 data_hovercard_url = request.route_path('hovercard_user', user_id=getattr(user, 'user_id', ''))
227 227 gravatar_class = ' '.join(gravatar_class)
228 228
229 229 %>
230 230 <%doc>
231 231 TODO: johbo: For now we serve double size images to make it smooth
232 232 for retina. This is how it worked until now. Should be replaced
233 233 with a better solution at some point.
234 234 </%doc>
235 235
236 <img class="${gravatar_class}" height="${size}" width="${size}" data-hovercard-url="${data_hovercard_url}" data-hovercard-alt="${data_hovercard_alt}" src="${h.gravatar_url(email, size * 2)}" />
236 <img class="${gravatar_class}" height="${size}" width="${size}" data-hovercard-url="${data_hovercard_url}" data-hovercard-alt="${data_hovercard_alt}" src="${h.gravatar_url(email, size * 2, request=request)}" />
237 237 </%def>
238 238
239 239
240 240 <%def name="gravatar_with_user(contact, size=16, show_disabled=False, tooltip=False, _class='rc-user')">
241 241 <%
242 242 email = h.email_or_none(contact)
243 243 rc_user = h.discover_user(contact)
244 244 %>
245 245
246 246 <div class="${_class}">
247 247 ${self.gravatar(email, size, tooltip=tooltip, tooltip_alt=contact, user=rc_user)}
248 248 <span class="${('user user-disabled' if show_disabled else 'user')}">
249 249 ${h.link_to_user(rc_user or contact)}
250 250 </span>
251 251 </div>
252 252 </%def>
253 253
254 254
255 255 <%def name="user_group_icon(user_group=None, size=16, tooltip=False)">
256 256 <%
257 257 if (size > 16):
258 258 gravatar_class = 'icon-user-group-alt'
259 259 else:
260 260 gravatar_class = 'icon-user-group-alt'
261 261
262 262 if tooltip:
263 263 gravatar_class += ' tooltip-hovercard'
264 264
265 265 data_hovercard_url = request.route_path('hovercard_user_group', user_group_id=user_group.users_group_id)
266 266 %>
267 267 <%doc>
268 268 TODO: johbo: For now we serve double size images to make it smooth
269 269 for retina. This is how it worked until now. Should be replaced
270 270 with a better solution at some point.
271 271 </%doc>
272 272
273 273 <i style="font-size: ${size}px" class="${gravatar_class} x-icon-size-${size}" data-hovercard-url="${data_hovercard_url}"></i>
274 274 </%def>
275 275
276 276 <%def name="repo_page_title(repo_instance)">
277 277 <div class="title-content repo-title">
278 278
279 279 <div class="title-main">
280 280 ## SVN/HG/GIT icons
281 281 %if h.is_hg(repo_instance):
282 282 <i class="icon-hg"></i>
283 283 %endif
284 284 %if h.is_git(repo_instance):
285 285 <i class="icon-git"></i>
286 286 %endif
287 287 %if h.is_svn(repo_instance):
288 288 <i class="icon-svn"></i>
289 289 %endif
290 290
291 291 ## public/private
292 292 %if repo_instance.private:
293 293 <i class="icon-repo-private"></i>
294 294 %else:
295 295 <i class="icon-repo-public"></i>
296 296 %endif
297 297
298 298 ## repo name with group name
299 299 ${h.breadcrumb_repo_link(repo_instance)}
300 300
301 301 ## Context Actions
302 302 <div class="pull-right">
303 303 %if c.rhodecode_user.username != h.DEFAULT_USER:
304 304 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid, _query=dict(auth_token=c.rhodecode_user.feed_token))}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
305 305
306 306 <a href="#WatchRepo" onclick="toggleFollowingRepo(this, templateContext.repo_id); return false" title="${_('Watch this Repository and actions on it in your personalized journal')}" class="btn btn-sm ${('watching' if c.repository_is_user_following else '')}">
307 307 % if c.repository_is_user_following:
308 308 <i class="icon-eye-off"></i>${_('Unwatch')}
309 309 % else:
310 310 <i class="icon-eye"></i>${_('Watch')}
311 311 % endif
312 312
313 313 </a>
314 314 %else:
315 315 <a href="${h.route_path('atom_feed_home', repo_name=c.rhodecode_db_repo.repo_uid)}" title="${_('RSS Feed')}" class="btn btn-sm"><i class="icon-rss-sign"></i>RSS</a>
316 316 %endif
317 317 </div>
318 318
319 319 </div>
320 320
321 321 ## FORKED
322 322 %if repo_instance.fork:
323 323 <p class="discreet">
324 324 <i class="icon-code-fork"></i> ${_('Fork of')}
325 325 ${h.link_to_if(c.has_origin_repo_read_perm,repo_instance.fork.repo_name, h.route_path('repo_summary', repo_name=repo_instance.fork.repo_name))}
326 326 </p>
327 327 %endif
328 328
329 329 ## IMPORTED FROM REMOTE
330 330 %if repo_instance.clone_uri:
331 331 <p class="discreet">
332 332 <i class="icon-code-fork"></i> ${_('Clone from')}
333 333 <a href="${h.safe_str(h.hide_credentials(repo_instance.clone_uri))}">${h.hide_credentials(repo_instance.clone_uri)}</a>
334 334 </p>
335 335 %endif
336 336
337 337 ## LOCKING STATUS
338 338 %if repo_instance.locked[0]:
339 339 <p class="locking_locked discreet">
340 340 <i class="icon-repo-lock"></i>
341 341 ${_('Repository locked by %(user)s') % {'user': h.person_by_id(repo_instance.locked[0])}}
342 342 </p>
343 343 %elif repo_instance.enable_locking:
344 344 <p class="locking_unlocked discreet">
345 345 <i class="icon-repo-unlock"></i>
346 346 ${_('Repository not locked. Pull repository to lock it.')}
347 347 </p>
348 348 %endif
349 349
350 350 </div>
351 351 </%def>
352 352
353 353 <%def name="repo_menu(active=None)">
354 354 <%
355 355 ## determine if we have "any" option available
356 356 can_lock = h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.rhodecode_db_repo.enable_locking
357 357 has_actions = can_lock
358 358
359 359 %>
360 360 % if c.rhodecode_db_repo.archived:
361 361 <div class="alert alert-warning text-center">
362 362 <strong>${_('This repository has been archived. It is now read-only.')}</strong>
363 363 </div>
364 364 % endif
365 365
366 366 <!--- REPO CONTEXT BAR -->
367 367 <div id="context-bar">
368 368 <div class="wrapper">
369 369
370 370 <div class="title">
371 371 ${self.repo_page_title(c.rhodecode_db_repo)}
372 372 </div>
373 373
374 374 <ul id="context-pages" class="navigation horizontal-list">
375 375 <li class="${h.is_active('summary', active)}"><a class="menulink" href="${h.route_path('repo_summary_explicit', repo_name=c.repo_name)}"><div class="menulabel">${_('Summary')}</div></a></li>
376 376 <li class="${h.is_active('commits', active)}"><a class="menulink" href="${h.route_path('repo_commits', repo_name=c.repo_name)}"><div class="menulabel">${_('Commits')}</div></a></li>
377 377 <li class="${h.is_active('files', active)}"><a class="menulink" href="${h.repo_files_by_ref_url(c.repo_name, c.rhodecode_db_repo.repo_type, f_path='', ref_name=c.rhodecode_db_repo.landing_ref_name, commit_id='tip', query={'at':c.rhodecode_db_repo.landing_ref_name})}"><div class="menulabel">${_('Files')}</div></a></li>
378 378 <li class="${h.is_active('compare', active)}"><a class="menulink" href="${h.route_path('repo_compare_select',repo_name=c.repo_name)}"><div class="menulabel">${_('Compare')}</div></a></li>
379 379
380 380 ## TODO: anderson: ideally it would have a function on the scm_instance "enable_pullrequest() and enable_fork()"
381 381 %if c.rhodecode_db_repo.repo_type in ['git','hg']:
382 382 <li class="${h.is_active('showpullrequest', active)}">
383 383 <a class="menulink" href="${h.route_path('pullrequest_show_all', repo_name=c.repo_name)}" title="${h.tooltip(_('Show Pull Requests for %s') % c.repo_name)}">
384 384 <div class="menulabel">
385 385 ${_('Pull Requests')} <span class="menulink-counter">${c.repository_pull_requests}</span>
386 386 </div>
387 387 </a>
388 388 </li>
389 389 %endif
390 390
391 391 <li class="${h.is_active('artifacts', active)}">
392 392 <a class="menulink" href="${h.route_path('repo_artifacts_list',repo_name=c.repo_name)}">
393 393 <div class="menulabel">
394 394 ${_('Artifacts')} <span class="menulink-counter">${c.repository_artifacts}</span>
395 395 </div>
396 396 </a>
397 397 </li>
398 398
399 399 %if not c.rhodecode_db_repo.archived and h.HasRepoPermissionAll('repository.admin')(c.repo_name):
400 400 <li class="${h.is_active('settings', active)}"><a class="menulink" href="${h.route_path('edit_repo',repo_name=c.repo_name)}"><div class="menulabel">${_('Repository Settings')}</div></a></li>
401 401 %endif
402 402
403 403 <li class="${h.is_active('options', active)}">
404 404 % if has_actions:
405 405 <a class="menulink dropdown">
406 406 <div class="menulabel">${_('Options')}<div class="show_more"></div></div>
407 407 </a>
408 408 <ul class="submenu">
409 409 %if can_lock:
410 410 %if c.rhodecode_db_repo.locked[0]:
411 411 <li><a class="locking_del" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Unlock Repository')}</a></li>
412 412 %else:
413 413 <li><a class="locking_add" href="${h.route_path('repo_edit_toggle_locking',repo_name=c.repo_name)}">${_('Lock Repository')}</a></li>
414 414 %endif
415 415 %endif
416 416 </ul>
417 417 % endif
418 418 </li>
419 419
420 420 </ul>
421 421 </div>
422 422 <div class="clear"></div>
423 423 </div>
424 424
425 425 <!--- REPO END CONTEXT BAR -->
426 426
427 427 </%def>
428 428
429 429 <%def name="repo_group_page_title(repo_group_instance)">
430 430 <div class="title-content">
431 431 <div class="title-main">
432 432 ## Repository Group icon
433 433 <i class="icon-repo-group"></i>
434 434
435 435 ## repo name with group name
436 436 ${h.breadcrumb_repo_group_link(repo_group_instance)}
437 437 </div>
438 438
439 439 <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
440 440 <div class="repo-group-desc discreet">
441 441 ${dt.repo_group_desc(repo_group_instance.description_safe, repo_group_instance.personal, c.visual.stylify_metatags)}
442 442 </div>
443 443
444 444 </div>
445 445 </%def>
446 446
447 447
448 448 <%def name="repo_group_menu(active=None)">
449 449 <%
450 450 gr_name = c.repo_group.group_name if c.repo_group else None
451 451 # create repositories with write permission on group is set to true
452 452 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
453 453
454 454 %>
455 455
456 456
457 457 <!--- REPO GROUP CONTEXT BAR -->
458 458 <div id="context-bar">
459 459 <div class="wrapper">
460 460 <div class="title">
461 461 ${self.repo_group_page_title(c.repo_group)}
462 462 </div>
463 463
464 464 <ul id="context-pages" class="navigation horizontal-list">
465 465 <li class="${h.is_active('home', active)}">
466 466 <a class="menulink" href="${h.route_path('repo_group_home', repo_group_name=c.repo_group.group_name)}"><div class="menulabel">${_('Group Home')}</div></a>
467 467 </li>
468 468 % if c.is_super_admin or group_admin:
469 469 <li class="${h.is_active('settings', active)}">
470 470 <a class="menulink" href="${h.route_path('edit_repo_group',repo_group_name=c.repo_group.group_name)}" title="${_('You have admin right to this group, and can edit it')}"><div class="menulabel">${_('Group Settings')}</div></a>
471 471 </li>
472 472 % endif
473 473
474 474 </ul>
475 475 </div>
476 476 <div class="clear"></div>
477 477 </div>
478 478
479 479 <!--- REPO GROUP CONTEXT BAR -->
480 480
481 481 </%def>
482 482
483 483
484 484 <%def name="usermenu(active=False)">
485 485 <%
486 486 not_anonymous = c.rhodecode_user.username != h.DEFAULT_USER
487 487
488 488 gr_name = c.repo_group.group_name if (hasattr(c, 'repo_group') and c.repo_group) else None
489 489 # create repositories with write permission on group is set to true
490 490
491 491 can_fork = c.is_super_admin or h.HasPermissionAny('hg.fork.repository')()
492 492 create_on_write = h.HasPermissionAny('hg.create.write_on_repogroup.true')()
493 493 group_write = h.HasRepoGroupPermissionAny('group.write')(gr_name, 'can write into group index page')
494 494 group_admin = h.HasRepoGroupPermissionAny('group.admin')(gr_name, 'group admin index page')
495 495
496 496 can_create_repos = c.is_super_admin or c.can_create_repo
497 497 can_create_repo_groups = c.is_super_admin or c.can_create_repo_group
498 498
499 499 can_create_repos_in_group = c.is_super_admin or group_admin or (group_write and create_on_write)
500 500 can_create_repo_groups_in_group = c.is_super_admin or group_admin
501 501 %>
502 502
503 503 % if not_anonymous:
504 504 <%
505 505 default_target_group = dict()
506 506 if c.rhodecode_user.personal_repo_group:
507 507 default_target_group = dict(parent_group=c.rhodecode_user.personal_repo_group.group_id)
508 508 %>
509 509
510 510 ## create action
511 511 <li>
512 512 <a href="#create-actions" onclick="return false;" class="menulink childs">
513 513 <i class="icon-plus-circled"></i>
514 514 </a>
515 515
516 516 <div class="action-menu submenu">
517 517
518 518 <ol>
519 519 ## scope of within a repository
520 520 % if hasattr(c, 'rhodecode_db_repo') and c.rhodecode_db_repo:
521 521 <li class="submenu-title">${_('This Repository')}</li>
522 522 <li>
523 523 <a href="${h.route_path('pullrequest_new',repo_name=c.repo_name)}">${_('Create Pull Request')}</a>
524 524 </li>
525 525 % if can_fork:
526 526 <li>
527 527 <a href="${h.route_path('repo_fork_new',repo_name=c.repo_name,_query=default_target_group)}">${_('Fork this repository')}</a>
528 528 </li>
529 529 % endif
530 530 % endif
531 531
532 532 ## scope of within repository groups
533 533 % if hasattr(c, 'repo_group') and c.repo_group and (can_create_repos_in_group or can_create_repo_groups_in_group):
534 534 <li class="submenu-title">${_('This Repository Group')}</li>
535 535
536 536 % if can_create_repos_in_group:
537 537 <li>
538 538 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.repo_group.group_id))}">${_('New Repository')}</a>
539 539 </li>
540 540 % endif
541 541
542 542 % if can_create_repo_groups_in_group:
543 543 <li>
544 544 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.repo_group.group_id))}">${_(u'New Repository Group')}</a>
545 545 </li>
546 546 % endif
547 547 % endif
548 548
549 549 ## personal group
550 550 % if c.rhodecode_user.personal_repo_group:
551 551 <li class="submenu-title">Personal Group</li>
552 552
553 553 <li>
554 554 <a href="${h.route_path('repo_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}" >${_('New Repository')} </a>
555 555 </li>
556 556
557 557 <li>
558 558 <a href="${h.route_path('repo_group_new',_query=dict(parent_group=c.rhodecode_user.personal_repo_group.group_id))}">${_('New Repository Group')} </a>
559 559 </li>
560 560 % endif
561 561
562 562 ## Global actions
563 563 <li class="submenu-title">RhodeCode</li>
564 564 % if can_create_repos:
565 565 <li>
566 566 <a href="${h.route_path('repo_new')}" >${_('New Repository')}</a>
567 567 </li>
568 568 % endif
569 569
570 570 % if can_create_repo_groups:
571 571 <li>
572 572 <a href="${h.route_path('repo_group_new')}" >${_(u'New Repository Group')}</a>
573 573 </li>
574 574 % endif
575 575
576 576 <li>
577 577 <a href="${h.route_path('gists_new')}">${_(u'New Gist')}</a>
578 578 </li>
579 579
580 580 </ol>
581 581
582 582 </div>
583 583 </li>
584 584
585 585 ## notifications
586 586 <li>
587 587 <a class="${('empty' if c.unread_notifications == 0 else '')}" href="${h.route_path('notifications_show_all')}">
588 588 ${c.unread_notifications}
589 589 </a>
590 590 </li>
591 591 % endif
592 592
593 593 ## USER MENU
594 594 <li id="quick_login_li" class="${'active' if active else ''}">
595 595 % if c.rhodecode_user.username == h.DEFAULT_USER:
596 596 <a id="quick_login_link" class="menulink childs" href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">
597 597 ${gravatar(c.rhodecode_user.email, 20)}
598 598 <span class="user">
599 599 <span>${_('Sign in')}</span>
600 600 </span>
601 601 </a>
602 602 % else:
603 603 ## logged in user
604 604 <a id="quick_login_link" class="menulink childs">
605 605 ${gravatar(c.rhodecode_user.email, 20)}
606 606 <span class="user">
607 607 <span class="menu_link_user">${c.rhodecode_user.username}</span>
608 608 <div class="show_more"></div>
609 609 </span>
610 610 </a>
611 611 ## subnav with menu for logged in user
612 612 <div class="user-menu submenu">
613 613 <div id="quick_login">
614 614 %if c.rhodecode_user.username != h.DEFAULT_USER:
615 615 <div class="">
616 616 <div class="big_gravatar">${gravatar(c.rhodecode_user.email, 48)}</div>
617 617 <div class="full_name">${c.rhodecode_user.full_name_or_username}</div>
618 618 <div class="email">${c.rhodecode_user.email}</div>
619 619 </div>
620 620 <div class="">
621 621 <ol class="links">
622 622 <li>${h.link_to(_(u'My account'),h.route_path('my_account_profile'))}</li>
623 623 % if c.rhodecode_user.personal_repo_group:
624 624 <li>${h.link_to(_(u'My personal group'), h.route_path('repo_group_home', repo_group_name=c.rhodecode_user.personal_repo_group.group_name))}</li>
625 625 % endif
626 626 <li>${h.link_to(_(u'Pull Requests'), h.route_path('my_account_pullrequests'))}</li>
627 627
628 628 % if c.debug_style:
629 629 <li>
630 630 <a class="menulink" title="${_('Style')}" href="${h.route_path('debug_style_home')}">
631 631 <div class="menulabel">${_('[Style]')}</div>
632 632 </a>
633 633 </li>
634 634 % endif
635 635
636 636 ## bookmark-items
637 637 <li class="bookmark-items">
638 638 ${_('Bookmarks')}
639 639 <div class="pull-right">
640 640 <a href="${h.route_path('my_account_bookmarks')}">
641 641
642 642 <i class="icon-cog"></i>
643 643 </a>
644 644 </div>
645 645 </li>
646 646 % if not c.bookmark_items:
647 647 <li>
648 648 <a href="${h.route_path('my_account_bookmarks')}">${_('No Bookmarks yet.')}</a>
649 649 </li>
650 650 % endif
651 651 % for item in c.bookmark_items:
652 652 <li>
653 653 % if item.repository:
654 654 <div>
655 655 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
656 656 <code>${item.position}</code>
657 657 % if item.repository.repo_type == 'hg':
658 658 <i class="icon-hg" title="${_('Repository')}" style="font-size: 16px"></i>
659 659 % elif item.repository.repo_type == 'git':
660 660 <i class="icon-git" title="${_('Repository')}" style="font-size: 16px"></i>
661 661 % elif item.repository.repo_type == 'svn':
662 662 <i class="icon-svn" title="${_('Repository')}" style="font-size: 16px"></i>
663 663 % endif
664 664 ${(item.title or h.shorter(item.repository.repo_name, 30))}
665 665 </a>
666 666 </div>
667 667 % elif item.repository_group:
668 668 <div>
669 669 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
670 670 <code>${item.position}</code>
671 671 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
672 672 ${(item.title or h.shorter(item.repository_group.group_name, 30))}
673 673 </a>
674 674 </div>
675 675 % else:
676 676 <a class="bookmark-item" href="${h.route_path('my_account_goto_bookmark', bookmark_id=item.position)}">
677 677 <code>${item.position}</code>
678 678 ${item.title}
679 679 </a>
680 680 % endif
681 681 </li>
682 682 % endfor
683 683
684 684 <li class="logout">
685 685 ${h.secure_form(h.route_path('logout'), request=request)}
686 686 ${h.submit('log_out', _(u'Sign Out'),class_="btn btn-primary")}
687 687 ${h.end_form()}
688 688 </li>
689 689 </ol>
690 690 </div>
691 691 %endif
692 692 </div>
693 693 </div>
694 694
695 695 % endif
696 696 </li>
697 697 </%def>
698 698
699 699 <%def name="menu_items(active=None)">
700 700 <%
701 701 notice_messages, notice_level = c.rhodecode_user.get_notice_messages()
702 702 notice_display = 'none' if len(notice_messages) == 0 else ''
703 703 %>
704 704
705 705 <ul id="quick" class="main_nav navigation horizontal-list">
706 706 ## notice box for important system messages
707 707 <li style="display: ${notice_display}">
708 708 <a class="notice-box" href="#openNotice" onclick="$('.notice-messages-container').toggle(); return false">
709 709 <div class="menulabel-notice ${notice_level}" >
710 710 ${len(notice_messages)}
711 711 </div>
712 712 </a>
713 713 </li>
714 714 <div class="notice-messages-container" style="display: none">
715 715 <div class="notice-messages">
716 716 <table class="rctable">
717 717 % for notice in notice_messages:
718 718 <tr id="notice-message-${notice['msg_id']}" class="notice-message-${notice['level']}">
719 719 <td style="vertical-align: text-top; width: 20px">
720 720 <i class="tooltip icon-info notice-color-${notice['level']}" title="${notice['level']}"></i>
721 721 </td>
722 722 <td>
723 723 <span><i class="icon-plus-squared cursor-pointer" onclick="$('#notice-${notice['msg_id']}').toggle()"></i> </span>
724 724 ${notice['subject']}
725 725
726 726 <div id="notice-${notice['msg_id']}" style="display: none">
727 727 ${h.render(notice['body'], renderer='markdown')}
728 728 </div>
729 729 </td>
730 730 <td style="vertical-align: text-top; width: 35px;">
731 731 <a class="tooltip" title="${_('dismiss')}" href="#dismiss" onclick="dismissNotice(${notice['msg_id']});return false">
732 732 <i class="icon-remove icon-filled-red"></i>
733 733 </a>
734 734 </td>
735 735 </tr>
736 736
737 737 % endfor
738 738 </table>
739 739 </div>
740 740 </div>
741 741 ## Main filter
742 742 <li>
743 743 <div class="menulabel main_filter_box">
744 744 <div class="main_filter_input_box">
745 745 <ul class="searchItems">
746 746
747 747 <li class="searchTag searchTagIcon">
748 748 <i class="icon-search"></i>
749 749 </li>
750 750
751 751 % if c.template_context['search_context']['repo_id']:
752 752 <li class="searchTag searchTagFilter searchTagHidable" >
753 753 ##<a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">
754 754 <span class="tag">
755 755 This repo
756 756 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
757 757 </span>
758 758 ##</a>
759 759 </li>
760 760 % elif c.template_context['search_context']['repo_group_id']:
761 761 <li class="searchTag searchTagFilter searchTagHidable">
762 762 ##<a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">
763 763 <span class="tag">
764 764 This group
765 765 <a href="#removeGoToFilter" onclick="removeGoToFilter(); return false"><i class="icon-cancel-circled"></i></a>
766 766 </span>
767 767 ##</a>
768 768 </li>
769 769 % endif
770 770
771 771 <li class="searchTagInput">
772 772 <input class="main_filter_input" id="main_filter" size="25" type="text" name="main_filter" placeholder="${_('search / go to...')}" value="" />
773 773 </li>
774 774 <li class="searchTag searchTagHelp">
775 775 <a href="#showFilterHelp" onclick="showMainFilterBox(); return false">?</a>
776 776 </li>
777 777 </ul>
778 778 </div>
779 779 </div>
780 780
781 781 <div id="main_filter_help" style="display: none">
782 782 - Use '/' key to quickly access this field.
783 783
784 784 - Enter a name of repository, or repository group for quick search.
785 785
786 786 - Prefix query to allow special search:
787 787
788 788 <strong>user:</strong>admin, to search for usernames, always global
789 789
790 790 <strong>user_group:</strong>devops, to search for user groups, always global
791 791
792 792 <strong>pr:</strong>303, to search for pull request number, title, or description, always global
793 793
794 794 <strong>commit:</strong>efced4, to search for commits, scoped to repositories or groups
795 795
796 796 <strong>file:</strong>models.py, to search for file paths, scoped to repositories or groups
797 797
798 798 % if c.template_context['search_context']['repo_id']:
799 799 For advanced full text search visit: <a href="${h.route_path('search_repo',repo_name=c.template_context['search_context']['repo_name'])}">repository search</a>
800 800 % elif c.template_context['search_context']['repo_group_id']:
801 801 For advanced full text search visit: <a href="${h.route_path('search_repo_group',repo_group_name=c.template_context['search_context']['repo_group_name'])}">repository group search</a>
802 802 % else:
803 803 For advanced full text search visit: <a href="${h.route_path('search')}">global search</a>
804 804 % endif
805 805 </div>
806 806 </li>
807 807
808 808 ## ROOT MENU
809 809 <li class="${h.is_active('home', active)}">
810 810 <a class="menulink" title="${_('Home')}" href="${h.route_path('home')}">
811 811 <div class="menulabel">${_('Home')}</div>
812 812 </a>
813 813 </li>
814 814
815 815 %if c.rhodecode_user.username != h.DEFAULT_USER:
816 816 <li class="${h.is_active('journal', active)}">
817 817 <a class="menulink" title="${_('Show activity journal')}" href="${h.route_path('journal')}">
818 818 <div class="menulabel">${_('Journal')}</div>
819 819 </a>
820 820 </li>
821 821 %else:
822 822 <li class="${h.is_active('journal', active)}">
823 823 <a class="menulink" title="${_('Show Public activity journal')}" href="${h.route_path('journal_public')}">
824 824 <div class="menulabel">${_('Public journal')}</div>
825 825 </a>
826 826 </li>
827 827 %endif
828 828
829 829 <li class="${h.is_active('gists', active)}">
830 830 <a class="menulink childs" title="${_('Show Gists')}" href="${h.route_path('gists_show')}">
831 831 <div class="menulabel">${_('Gists')}</div>
832 832 </a>
833 833 </li>
834 834
835 835 % if c.is_super_admin or c.is_delegated_admin:
836 836 <li class="${h.is_active('admin', active)}">
837 837 <a class="menulink childs" title="${_('Admin settings')}" href="${h.route_path('admin_home')}">
838 838 <div class="menulabel">${_('Admin')} </div>
839 839 </a>
840 840 </li>
841 841 % endif
842 842
843 843 ## render extra user menu
844 844 ${usermenu(active=(active=='my_account'))}
845 845
846 846 </ul>
847 847
848 848 <script type="text/javascript">
849 849 var visualShowPublicIcon = "${c.visual.show_public_icon}" == "True";
850 850
851 851 var formatRepoResult = function(result, container, query, escapeMarkup) {
852 852 return function(data, escapeMarkup) {
853 853 if (!data.repo_id){
854 854 return data.text; // optgroup text Repositories
855 855 }
856 856
857 857 var tmpl = '';
858 858 var repoType = data['repo_type'];
859 859 var repoName = data['text'];
860 860
861 861 if(data && data.type == 'repo'){
862 862 if(repoType === 'hg'){
863 863 tmpl += '<i class="icon-hg"></i> ';
864 864 }
865 865 else if(repoType === 'git'){
866 866 tmpl += '<i class="icon-git"></i> ';
867 867 }
868 868 else if(repoType === 'svn'){
869 869 tmpl += '<i class="icon-svn"></i> ';
870 870 }
871 871 if(data['private']){
872 872 tmpl += '<i class="icon-lock" ></i> ';
873 873 }
874 874 else if(visualShowPublicIcon){
875 875 tmpl += '<i class="icon-unlock-alt"></i> ';
876 876 }
877 877 }
878 878 tmpl += escapeMarkup(repoName);
879 879 return tmpl;
880 880
881 881 }(result, escapeMarkup);
882 882 };
883 883
884 884 var formatRepoGroupResult = function(result, container, query, escapeMarkup) {
885 885 return function(data, escapeMarkup) {
886 886 if (!data.repo_group_id){
887 887 return data.text; // optgroup text Repositories
888 888 }
889 889
890 890 var tmpl = '';
891 891 var repoGroupName = data['text'];
892 892
893 893 if(data){
894 894
895 895 tmpl += '<i class="icon-repo-group"></i> ';
896 896
897 897 }
898 898 tmpl += escapeMarkup(repoGroupName);
899 899 return tmpl;
900 900
901 901 }(result, escapeMarkup);
902 902 };
903 903
904 904 var escapeRegExChars = function (value) {
905 905 return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
906 906 };
907 907
908 908 var getRepoIcon = function(repo_type) {
909 909 if (repo_type === 'hg') {
910 910 return '<i class="icon-hg"></i> ';
911 911 }
912 912 else if (repo_type === 'git') {
913 913 return '<i class="icon-git"></i> ';
914 914 }
915 915 else if (repo_type === 'svn') {
916 916 return '<i class="icon-svn"></i> ';
917 917 }
918 918 return ''
919 919 };
920 920
921 921 var autocompleteMainFilterFormatResult = function (data, value, org_formatter) {
922 922
923 923 if (value.split(':').length === 2) {
924 924 value = value.split(':')[1]
925 925 }
926 926
927 927 var searchType = data['type'];
928 928 var searchSubType = data['subtype'];
929 929 var valueDisplay = data['value_display'];
930 930 var valueIcon = data['value_icon'];
931 931
932 932 var pattern = '(' + escapeRegExChars(value) + ')';
933 933
934 934 valueDisplay = Select2.util.escapeMarkup(valueDisplay);
935 935
936 936 // highlight match
937 937 if (searchType != 'text') {
938 938 valueDisplay = valueDisplay.replace(new RegExp(pattern, 'gi'), '<strong>$1<\/strong>');
939 939 }
940 940
941 941 var icon = '';
942 942
943 943 if (searchType === 'hint') {
944 944 icon += '<i class="icon-repo-group"></i> ';
945 945 }
946 946 // full text search/hints
947 947 else if (searchType === 'search') {
948 948 if (valueIcon === undefined) {
949 949 icon += '<i class="icon-more"></i> ';
950 950 } else {
951 951 icon += valueIcon + ' ';
952 952 }
953 953
954 954 if (searchSubType !== undefined && searchSubType == 'repo') {
955 955 valueDisplay += '<div class="pull-right tag">repository</div>';
956 956 }
957 957 else if (searchSubType !== undefined && searchSubType == 'repo_group') {
958 958 valueDisplay += '<div class="pull-right tag">repo group</div>';
959 959 }
960 960 }
961 961 // repository
962 962 else if (searchType === 'repo') {
963 963
964 964 var repoIcon = getRepoIcon(data['repo_type']);
965 965 icon += repoIcon;
966 966
967 967 if (data['private']) {
968 968 icon += '<i class="icon-lock" ></i> ';
969 969 }
970 970 else if (visualShowPublicIcon) {
971 971 icon += '<i class="icon-unlock-alt"></i> ';
972 972 }
973 973 }
974 974 // repository groups
975 975 else if (searchType === 'repo_group') {
976 976 icon += '<i class="icon-repo-group"></i> ';
977 977 }
978 978 // user group
979 979 else if (searchType === 'user_group') {
980 980 icon += '<i class="icon-group"></i> ';
981 981 }
982 982 // user
983 983 else if (searchType === 'user') {
984 984 icon += '<img class="gravatar" src="{0}"/>'.format(data['icon_link']);
985 985 }
986 986 // pull request
987 987 else if (searchType === 'pull_request') {
988 988 icon += '<i class="icon-merge"></i> ';
989 989 }
990 990 // commit
991 991 else if (searchType === 'commit') {
992 992 var repo_data = data['repo_data'];
993 993 var repoIcon = getRepoIcon(repo_data['repository_type']);
994 994 if (repoIcon) {
995 995 icon += repoIcon;
996 996 } else {
997 997 icon += '<i class="icon-tag"></i>';
998 998 }
999 999 }
1000 1000 // file
1001 1001 else if (searchType === 'file') {
1002 1002 var repo_data = data['repo_data'];
1003 1003 var repoIcon = getRepoIcon(repo_data['repository_type']);
1004 1004 if (repoIcon) {
1005 1005 icon += repoIcon;
1006 1006 } else {
1007 1007 icon += '<i class="icon-tag"></i>';
1008 1008 }
1009 1009 }
1010 1010 // generic text
1011 1011 else if (searchType === 'text') {
1012 1012 icon = '';
1013 1013 }
1014 1014
1015 1015 var tmpl = '<div class="ac-container-wrap">{0}{1}</div>';
1016 1016 return tmpl.format(icon, valueDisplay);
1017 1017 };
1018 1018
1019 1019 var handleSelect = function(element, suggestion) {
1020 1020 if (suggestion.type === "hint") {
1021 1021 // we skip action
1022 1022 $('#main_filter').focus();
1023 1023 }
1024 1024 else if (suggestion.type === "text") {
1025 1025 // we skip action
1026 1026 $('#main_filter').focus();
1027 1027
1028 1028 } else {
1029 1029 window.location = suggestion['url'];
1030 1030 }
1031 1031 };
1032 1032
1033 1033 var autocompleteMainFilterResult = function (suggestion, originalQuery, queryLowerCase) {
1034 1034 if (queryLowerCase.split(':').length === 2) {
1035 1035 queryLowerCase = queryLowerCase.split(':')[1]
1036 1036 }
1037 1037 if (suggestion.type === "text") {
1038 1038 // special case we don't want to "skip" display for
1039 1039 return true
1040 1040 }
1041 1041 return suggestion.value_display.toLowerCase().indexOf(queryLowerCase) !== -1;
1042 1042 };
1043 1043
1044 1044 var cleanContext = {
1045 1045 repo_view_type: null,
1046 1046
1047 1047 repo_id: null,
1048 1048 repo_name: "",
1049 1049
1050 1050 repo_group_id: null,
1051 1051 repo_group_name: null
1052 1052 };
1053 1053 var removeGoToFilter = function () {
1054 1054 $('.searchTagHidable').hide();
1055 1055 $('#main_filter').autocomplete(
1056 1056 'setOptions', {params:{search_context: cleanContext}});
1057 1057 };
1058 1058
1059 1059 $('#main_filter').autocomplete({
1060 1060 serviceUrl: pyroutes.url('goto_switcher_data'),
1061 1061 params: {
1062 1062 "search_context": templateContext.search_context
1063 1063 },
1064 1064 minChars:2,
1065 1065 maxHeight:400,
1066 1066 deferRequestBy: 300, //miliseconds
1067 1067 tabDisabled: true,
1068 1068 autoSelectFirst: false,
1069 1069 containerClass: 'autocomplete-qfilter-suggestions',
1070 1070 formatResult: autocompleteMainFilterFormatResult,
1071 1071 lookupFilter: autocompleteMainFilterResult,
1072 1072 onSelect: function (element, suggestion) {
1073 1073 handleSelect(element, suggestion);
1074 1074 return false;
1075 1075 },
1076 1076 onSearchError: function (element, query, jqXHR, textStatus, errorThrown) {
1077 1077 if (jqXHR !== 'abort') {
1078 1078 var message = formatErrorMessage(jqXHR, textStatus, errorThrown);
1079 1079 SwalNoAnimation.fire({
1080 1080 icon: 'error',
1081 1081 title: _gettext('Error during search operation'),
1082 1082 html: '<span style="white-space: pre-line">{0}</span>'.format(message),
1083 1083 }).then(function(result) {
1084 1084 window.location.reload();
1085 1085 })
1086 1086 }
1087 1087 },
1088 1088 onSearchStart: function (params) {
1089 1089 $('.searchTag.searchTagIcon').html('<i class="icon-spin animate-spin"></i>')
1090 1090 },
1091 1091 onSearchComplete: function (query, suggestions) {
1092 1092 $('.searchTag.searchTagIcon').html('<i class="icon-search"></i>')
1093 1093 },
1094 1094 });
1095 1095
1096 1096 showMainFilterBox = function () {
1097 1097 $('#main_filter_help').toggle();
1098 1098 };
1099 1099
1100 1100 $('#main_filter').on('keydown.autocomplete', function (e) {
1101 1101
1102 1102 var BACKSPACE = 8;
1103 1103 var el = $(e.currentTarget);
1104 1104 if(e.which === BACKSPACE){
1105 1105 var inputVal = el.val();
1106 1106 if (inputVal === ""){
1107 1107 removeGoToFilter()
1108 1108 }
1109 1109 }
1110 1110 });
1111 1111
1112 1112 var dismissNotice = function(noticeId) {
1113 1113
1114 1114 var url = pyroutes.url('user_notice_dismiss',
1115 1115 {"user_id": templateContext.rhodecode_user.user_id});
1116 1116
1117 1117 var postData = {
1118 1118 'csrf_token': CSRF_TOKEN,
1119 1119 'notice_id': noticeId,
1120 1120 };
1121 1121
1122 1122 var success = function(response) {
1123 1123 $('#notice-message-' + noticeId).remove();
1124 1124 return false;
1125 1125 };
1126 1126 var failure = function(data, textStatus, xhr) {
1127 1127 alert("error processing request: " + textStatus);
1128 1128 return false;
1129 1129 };
1130 1130 ajaxPOST(url, postData, success, failure);
1131 1131 }
1132 1132
1133 1133 var hideLicenseWarning = function () {
1134 1134 var fingerprint = templateContext.session_attrs.license_fingerprint;
1135 1135 storeUserSessionAttr('rc_user_session_attr.hide_license_warning', fingerprint);
1136 1136 $('#notifications').hide();
1137 1137 }
1138 1138
1139 1139 var hideLicenseError = function () {
1140 1140 var fingerprint = templateContext.session_attrs.license_fingerprint;
1141 1141 storeUserSessionAttr('rc_user_session_attr.hide_license_error', fingerprint);
1142 1142 $('#notifications').hide();
1143 1143 }
1144 1144
1145 1145 </script>
1146 1146 <script src="${h.asset('js/rhodecode/base/keyboard-bindings.js', ver=c.rhodecode_version_hash)}"></script>
1147 1147 </%def>
1148 1148
1149 1149 <div class="modal" id="help_kb" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
1150 1150 <div class="modal-dialog">
1151 1151 <div class="modal-content">
1152 1152 <div class="modal-header">
1153 1153 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
1154 1154 <h4 class="modal-title" id="myModalLabel">${_('Keyboard shortcuts')}</h4>
1155 1155 </div>
1156 1156 <div class="modal-body">
1157 1157 <div class="block-left">
1158 1158 <table class="keyboard-mappings">
1159 1159 <tbody>
1160 1160 <tr>
1161 1161 <th></th>
1162 1162 <th>${_('Site-wide shortcuts')}</th>
1163 1163 </tr>
1164 1164 <%
1165 1165 elems = [
1166 1166 ('/', 'Use quick search box'),
1167 1167 ('g h', 'Goto home page'),
1168 1168 ('g g', 'Goto my private gists page'),
1169 1169 ('g G', 'Goto my public gists page'),
1170 1170 ('g 0-9', 'Goto bookmarked items from 0-9'),
1171 1171 ('n r', 'New repository page'),
1172 1172 ('n g', 'New gist page'),
1173 1173 ]
1174 1174 %>
1175 1175 %for key, desc in elems:
1176 1176 <tr>
1177 1177 <td class="keys">
1178 1178 <span class="key tag">${key}</span>
1179 1179 </td>
1180 1180 <td>${desc}</td>
1181 1181 </tr>
1182 1182 %endfor
1183 1183 </tbody>
1184 1184 </table>
1185 1185 </div>
1186 1186 <div class="block-left">
1187 1187 <table class="keyboard-mappings">
1188 1188 <tbody>
1189 1189 <tr>
1190 1190 <th></th>
1191 1191 <th>${_('Repositories')}</th>
1192 1192 </tr>
1193 1193 <%
1194 1194 elems = [
1195 1195 ('g s', 'Goto summary page'),
1196 1196 ('g c', 'Goto changelog page'),
1197 1197 ('g f', 'Goto files page'),
1198 1198 ('g F', 'Goto files page with file search activated'),
1199 1199 ('g p', 'Goto pull requests page'),
1200 1200 ('g o', 'Goto repository settings'),
1201 1201 ('g O', 'Goto repository access permissions settings'),
1202 1202 ('t s', 'Toggle sidebar on some pages'),
1203 1203 ]
1204 1204 %>
1205 1205 %for key, desc in elems:
1206 1206 <tr>
1207 1207 <td class="keys">
1208 1208 <span class="key tag">${key}</span>
1209 1209 </td>
1210 1210 <td>${desc}</td>
1211 1211 </tr>
1212 1212 %endfor
1213 1213 </tbody>
1214 1214 </table>
1215 1215 </div>
1216 1216 </div>
1217 1217 <div class="modal-footer">
1218 1218 </div>
1219 1219 </div><!-- /.modal-content -->
1220 1220 </div><!-- /.modal-dialog -->
1221 1221 </div><!-- /.modal -->
1222 1222
1223 1223
1224 1224 <script type="text/javascript">
1225 1225 (function () {
1226 1226 "use sctrict";
1227 1227
1228 1228 // details block auto-hide menu
1229 1229 $(document).mouseup(function(e) {
1230 1230 var container = $('.details-inline-block');
1231 1231 if (!container.is(e.target) && container.has(e.target).length === 0) {
1232 1232 $('.details-inline-block[open]').removeAttr('open')
1233 1233 }
1234 1234 });
1235 1235
1236 1236 var $sideBar = $('.right-sidebar');
1237 1237 var expanded = $sideBar.hasClass('right-sidebar-expanded');
1238 1238 var sidebarState = templateContext.session_attrs.sidebarState;
1239 1239 var sidebarEnabled = $('aside.right-sidebar').get(0);
1240 1240
1241 1241 if (sidebarState === 'expanded') {
1242 1242 expanded = true
1243 1243 } else if (sidebarState === 'collapsed') {
1244 1244 expanded = false
1245 1245 }
1246 1246 if (sidebarEnabled) {
1247 1247 // show sidebar since it's hidden on load
1248 1248 $('.right-sidebar').show();
1249 1249
1250 1250 // init based on set initial class, or if defined user session attrs
1251 1251 if (expanded) {
1252 1252 window.expandSidebar();
1253 1253 window.updateStickyHeader();
1254 1254
1255 1255 } else {
1256 1256 window.collapseSidebar();
1257 1257 window.updateStickyHeader();
1258 1258 }
1259 1259 }
1260 1260 })()
1261 1261
1262 1262 </script>
@@ -1,556 +1,556 b''
1 1 ## usage:
2 2 ## <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
3 3 ## ${comment.comment_block(comment)}
4 4 ##
5 5 <%namespace name="base" file="/base/base.mako"/>
6 6
7 7 <%!
8 8 from rhodecode.lib import html_filters
9 9 %>
10 10
11 11
12 12 <%def name="comment_block(comment, inline=False, active_pattern_entries=None, is_new=False)">
13 13
14 14 <%
15 15 from rhodecode.model.comment import CommentsModel
16 16 comment_model = CommentsModel()
17 17
18 18 comment_ver = comment.get_index_version(getattr(c, 'versions', []))
19 19 latest_ver = len(getattr(c, 'versions', []))
20 20 visible_for_user = True
21 21 if comment.draft:
22 22 visible_for_user = comment.user_id == c.rhodecode_user.user_id
23 23 %>
24 24
25 25 % if inline:
26 26 <% outdated_at_ver = comment.outdated_at_version(c.at_version_num) %>
27 27 % else:
28 28 <% outdated_at_ver = comment.older_than_version(c.at_version_num) %>
29 29 % endif
30 30
31 31 % if visible_for_user:
32 32 <div class="comment
33 33 ${'comment-inline' if inline else 'comment-general'}
34 34 ${'comment-outdated' if outdated_at_ver else 'comment-current'}"
35 35 id="comment-${comment.comment_id}"
36 36 line="${comment.line_no}"
37 37 data-comment-id="${comment.comment_id}"
38 38 data-comment-type="${comment.comment_type}"
39 39 data-comment-draft=${h.str_json(comment.draft)}
40 40 data-comment-renderer="${comment.renderer}"
41 41 data-comment-text="${comment.text | html_filters.base64,n}"
42 42 data-comment-f-path="${comment.f_path}"
43 43 data-comment-line-no="${comment.line_no}"
44 44 data-comment-inline=${h.str_json(inline)}
45 45 style="${'display: none;' if outdated_at_ver else ''}">
46 46
47 47 <div class="meta">
48 48 <div class="comment-type-label">
49 49 % if comment.draft:
50 50 <div class="tooltip comment-draft" title="${_('Draft comments are only visible to the author until submitted')}.">
51 51 DRAFT
52 52 </div>
53 53 % elif is_new:
54 54 <div class="tooltip comment-new" title="${_('This comment was added while you browsed this page')}.">
55 55 NEW
56 56 </div>
57 57 % endif
58 58
59 59 <div class="comment-label ${comment.comment_type or 'note'}" id="comment-label-${comment.comment_id}">
60 60
61 61 ## TODO COMMENT
62 62 % if comment.comment_type == 'todo':
63 63 % if comment.resolved:
64 64 <div class="resolved tooltip" title="${_('Resolved by comment #{}').format(comment.resolved.comment_id)}">
65 65 <i class="icon-flag-filled"></i>
66 66 <a href="#comment-${comment.resolved.comment_id}">${comment.comment_type}</a>
67 67 </div>
68 68 % else:
69 69 <div class="resolved tooltip" style="display: none">
70 70 <span>${comment.comment_type}</span>
71 71 </div>
72 72 <div class="resolve tooltip" onclick="return Rhodecode.comments.createResolutionComment(${comment.comment_id});" title="${_('Click to create resolution comment.')}">
73 73 <i class="icon-flag-filled"></i>
74 74 ${comment.comment_type}
75 75 </div>
76 76 % endif
77 77 ## NOTE COMMENT
78 78 % else:
79 79 ## RESOLVED NOTE
80 80 % if comment.resolved_comment:
81 81 <div class="tooltip" title="${_('This comment resolves TODO #{}').format(comment.resolved_comment.comment_id)}">
82 82 fix
83 83 <a href="#comment-${comment.resolved_comment.comment_id}" onclick="Rhodecode.comments.scrollToComment($('#comment-${comment.resolved_comment.comment_id}'), 0, ${h.str_json(comment.resolved_comment.outdated)})">
84 84 <span style="text-decoration: line-through">#${comment.resolved_comment.comment_id}</span>
85 85 </a>
86 86 </div>
87 87 ## STATUS CHANGE NOTE
88 88 % elif not comment.is_inline and comment.status_change:
89 89 <%
90 90 if comment.pull_request:
91 91 status_change_title = 'Status of review for pull request !{}'.format(comment.pull_request.pull_request_id)
92 92 else:
93 93 status_change_title = 'Status of review for commit {}'.format(h.short_id(comment.commit_id))
94 94 %>
95 95
96 96 <i class="icon-circle review-status-${comment.review_status}"></i>
97 97 <div class="changeset-status-lbl tooltip" title="${status_change_title}">
98 98 ${comment.review_status_lbl}
99 99 </div>
100 100 % else:
101 101 <div>
102 102 <i class="icon-comment"></i>
103 103 ${(comment.comment_type or 'note')}
104 104 </div>
105 105 % endif
106 106 % endif
107 107
108 108 </div>
109 109 </div>
110 110 ## NOTE 0 and .. => because we disable it for now until UI ready
111 111 % if 0 and comment.status_change:
112 112 <div class="pull-left">
113 113 <span class="tag authortag tooltip" title="${_('Status from pull request.')}">
114 114 <a href="${h.route_path('pullrequest_show',repo_name=comment.pull_request.target_repo.repo_name,pull_request_id=comment.pull_request.pull_request_id)}">
115 115 ${'!{}'.format(comment.pull_request.pull_request_id)}
116 116 </a>
117 117 </span>
118 118 </div>
119 119 % endif
120 120 ## Since only author can see drafts, we don't show it
121 121 % if not comment.draft:
122 122 <div class="author ${'author-inline' if inline else 'author-general'}">
123 123 ${base.gravatar_with_user(comment.author.email, 16, tooltip=True)}
124 124 </div>
125 125 % endif
126 126
127 127 <div class="date">
128 128 ${h.age_component(comment.modified_at, time_is_local=True)}
129 129 </div>
130 130
131 131 % if comment.pull_request and comment.pull_request.author.user_id == comment.author.user_id:
132 132 <span class="tag authortag tooltip" title="${_('Pull request author')}">
133 133 ${_('author')}
134 134 </span>
135 135 % endif
136 136
137 137 <%
138 138 comment_version_selector = 'comment_versions_{}'.format(comment.comment_id)
139 139 %>
140 140
141 141 % if comment.history:
142 142 <div class="date">
143 143
144 144 <input id="${comment_version_selector}" name="${comment_version_selector}"
145 145 type="hidden"
146 146 data-last-version="${comment.history[-1].version}">
147 147
148 148 <script type="text/javascript">
149 149
150 150 var preLoadVersionData = [
151 151 % for comment_history in comment.history:
152 152 {
153 153 id: ${comment_history.comment_history_id},
154 154 text: 'v${comment_history.version}',
155 155 action: function () {
156 156 Rhodecode.comments.showVersion(
157 157 "${comment.comment_id}",
158 158 "${comment_history.comment_history_id}"
159 159 )
160 160 },
161 161 comment_version: "${comment_history.version}",
162 162 comment_author_username: "${comment_history.author.username}",
163 comment_author_gravatar: "${h.gravatar_url(comment_history.author.email, 16)}",
163 comment_author_gravatar: "${h.gravatar_url(comment_history.author.email, 16, request=request)}",
164 164 comment_created_on: '${h.age_component(comment_history.created_on, time_is_local=True)}',
165 165 },
166 166 % endfor
167 167 ]
168 168 initVersionSelector("#${comment_version_selector}", {results: preLoadVersionData});
169 169
170 170 </script>
171 171
172 172 </div>
173 173 % else:
174 174 <div class="date" style="display: none">
175 175 <input id="${comment_version_selector}" name="${comment_version_selector}"
176 176 type="hidden"
177 177 data-last-version="0">
178 178 </div>
179 179 %endif
180 180
181 181 <div class="comment-links-block">
182 182
183 183 % if inline:
184 184 <a class="pr-version-inline" href="${request.current_route_path(_query=dict(version=comment.pull_request_version_id), _anchor='comment-{}'.format(comment.comment_id))}">
185 185 % if outdated_at_ver:
186 186 <strong class="comment-outdated-label">outdated</strong> <code class="tooltip pr-version-num" title="${_('Outdated comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}">${'v{}'.format(comment_ver)}</code>
187 187 <code class="action-divider">|</code>
188 188 % elif comment_ver:
189 189 <code class="tooltip pr-version-num" title="${_('Comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}">${'v{}'.format(comment_ver)}</code>
190 190 <code class="action-divider">|</code>
191 191 % endif
192 192 </a>
193 193 % else:
194 194 % if comment_ver:
195 195
196 196 % if comment.outdated:
197 197 <a class="pr-version"
198 198 href="?version=${comment.pull_request_version_id}#comment-${comment.comment_id}"
199 199 >
200 200 ${_('Outdated comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}
201 201 </a>
202 202 <code class="action-divider">|</code>
203 203 % else:
204 204 <a class="tooltip pr-version"
205 205 title="${_('Comment from pull request version v{0}, latest v{1}').format(comment_ver, latest_ver)}"
206 206 href="${h.route_path('pullrequest_show',repo_name=comment.pull_request.target_repo.repo_name,pull_request_id=comment.pull_request.pull_request_id, version=comment.pull_request_version_id)}"
207 207 >
208 208 <code class="pr-version-num">${'v{}'.format(comment_ver)}</code>
209 209 </a>
210 210 <code class="action-divider">|</code>
211 211 % endif
212 212
213 213 % endif
214 214 % endif
215 215
216 216 <details class="details-reset details-inline-block">
217 217 <summary class="noselect"><i class="icon-options cursor-pointer"></i></summary>
218 218 <details-menu class="details-dropdown">
219 219
220 220 <div class="dropdown-item">
221 221 ${_('Comment')} #${comment.comment_id}
222 222 <span class="pull-right icon-clipboard clipboard-action" data-clipboard-text="${comment_model.get_url(comment,request, permalink=True, anchor='comment-{}'.format(comment.comment_id))}" title="${_('Copy permalink')}"></span>
223 223 </div>
224 224
225 225 ## show delete comment if it's not a PR (regular comments) or it's PR that is not closed
226 226 ## only super-admin, repo admin OR comment owner can delete, also hide delete if currently viewed comment is outdated
227 227 %if not outdated_at_ver and (not comment.pull_request or (comment.pull_request and not comment.pull_request.is_closed())):
228 228 ## permissions to delete
229 229 %if comment.immutable is False and (c.is_super_admin or h.HasRepoPermissionAny('repository.admin')(c.repo_name) or comment.author.user_id == c.rhodecode_user.user_id):
230 230 <div class="dropdown-divider"></div>
231 231 <div class="dropdown-item">
232 232 <a onclick="return Rhodecode.comments.editComment(this, '${comment.line_no}', '${comment.f_path}');" class="btn btn-link btn-sm edit-comment">${_('Edit')}</a>
233 233 </div>
234 234 <div class="dropdown-item">
235 235 <a onclick="return Rhodecode.comments.deleteComment(this);" class="btn btn-link btn-sm btn-danger delete-comment">${_('Delete')}</a>
236 236 </div>
237 237 ## Only available in EE edition
238 238 % if comment.draft and c.rhodecode_edition_id == 'EE':
239 239 <div class="dropdown-item">
240 240 <a onclick="return Rhodecode.comments.finalizeDrafts([${comment.comment_id}]);" class="btn btn-link btn-sm finalize-draft-comment">${_('Submit draft')}</a>
241 241 </div>
242 242 % endif
243 243 %else:
244 244 <div class="dropdown-divider"></div>
245 245 <div class="dropdown-item">
246 246 <a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Edit')}</a>
247 247 </div>
248 248 <div class="dropdown-item">
249 249 <a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Delete')}</a>
250 250 </div>
251 251 %endif
252 252 %else:
253 253 <div class="dropdown-divider"></div>
254 254 <div class="dropdown-item">
255 255 <a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Edit')}</a>
256 256 </div>
257 257 <div class="dropdown-item">
258 258 <a class="tooltip edit-comment link-disabled" disabled="disabled" title="${_('Action unavailable')}">${_('Delete')}</a>
259 259 </div>
260 260 %endif
261 261 </details-menu>
262 262 </details>
263 263
264 264 <code class="action-divider">|</code>
265 265 % if outdated_at_ver:
266 266 <a onclick="return Rhodecode.comments.prevOutdatedComment(this);" class="tooltip prev-comment" title="${_('Jump to the previous outdated comment')}"> <i class="icon-angle-left"></i> </a>
267 267 <a onclick="return Rhodecode.comments.nextOutdatedComment(this);" class="tooltip next-comment" title="${_('Jump to the next outdated comment')}"> <i class="icon-angle-right"></i></a>
268 268 % else:
269 269 <a onclick="return Rhodecode.comments.prevComment(this);" class="tooltip prev-comment" title="${_('Jump to the previous comment')}"> <i class="icon-angle-left"></i></a>
270 270 <a onclick="return Rhodecode.comments.nextComment(this);" class="tooltip next-comment" title="${_('Jump to the next comment')}"> <i class="icon-angle-right"></i></a>
271 271 % endif
272 272
273 273 </div>
274 274 </div>
275 275 <div class="text">
276 276 ${h.render(comment.text, renderer=comment.renderer, mentions=True, repo_name=getattr(c, 'repo_name', None), active_pattern_entries=active_pattern_entries)}
277 277 </div>
278 278
279 279 </div>
280 280 % endif
281 281 </%def>
282 282
283 283 ## generate main comments
284 284 <%def name="generate_comments(comments, include_pull_request=False, is_pull_request=False)">
285 285 <%
286 286 active_pattern_entries = h.get_active_pattern_entries(getattr(c, 'repo_name', None))
287 287 %>
288 288
289 289 <div class="general-comments" id="comments">
290 290 %for comment in comments:
291 291 <div id="comment-tr-${comment.comment_id}">
292 292 ## only render comments that are not from pull request, or from
293 293 ## pull request and a status change
294 294 %if not comment.pull_request or (comment.pull_request and comment.status_change) or include_pull_request:
295 295 ${comment_block(comment, active_pattern_entries=active_pattern_entries)}
296 296 %endif
297 297 </div>
298 298 %endfor
299 299 ## to anchor ajax comments
300 300 <div id="injected_page_comments"></div>
301 301 </div>
302 302 </%def>
303 303
304 304
305 305 <%def name="comments(post_url, cur_status, is_pull_request=False, is_compare=False, change_status=True, form_extras=None)">
306 306
307 307 <div class="comments">
308 308 <%
309 309 if is_pull_request:
310 310 placeholder = _('Leave a comment on this Pull Request.')
311 311 elif is_compare:
312 312 placeholder = _('Leave a comment on {} commits in this range.').format(len(form_extras))
313 313 else:
314 314 placeholder = _('Leave a comment on this Commit.')
315 315 %>
316 316
317 317 % if c.rhodecode_user.username != h.DEFAULT_USER:
318 318 <div class="js-template" id="cb-comment-general-form-template">
319 319 ## template generated for injection
320 320 ${comment_form(form_type='general', review_statuses=c.commit_statuses, form_extras=form_extras)}
321 321 </div>
322 322
323 323 <div id="cb-comment-general-form-placeholder" class="comment-form ac">
324 324 ## inject form here
325 325 </div>
326 326 <script type="text/javascript">
327 327 var resolvesCommentId = null;
328 328 var generalCommentForm = Rhodecode.comments.createGeneralComment(
329 329 'general', "${placeholder}", resolvesCommentId);
330 330
331 331 // set custom success callback on rangeCommit
332 332 % if is_compare:
333 333 generalCommentForm.setHandleFormSubmit(function(o) {
334 334 var self = generalCommentForm;
335 335
336 336 var text = self.cm.getValue();
337 337 var status = self.getCommentStatus();
338 338 var commentType = self.getCommentType();
339 339 var isDraft = self.getDraftState();
340 340
341 341 if (text === "" && !status) {
342 342 return;
343 343 }
344 344
345 345 // we can pick which commits we want to make the comment by
346 346 // selecting them via click on preview pane, this will alter the hidden inputs
347 347 var cherryPicked = $('#changeset_compare_view_content .compare_select.hl').length > 0;
348 348
349 349 var commitIds = [];
350 350 $('#changeset_compare_view_content .compare_select').each(function(el) {
351 351 var commitId = this.id.replace('row-', '');
352 352 if ($(this).hasClass('hl') || !cherryPicked) {
353 353 $("input[data-commit-id='{0}']".format(commitId)).val(commitId);
354 354 commitIds.push(commitId);
355 355 } else {
356 356 $("input[data-commit-id='{0}']".format(commitId)).val('')
357 357 }
358 358 });
359 359
360 360 self.setActionButtonsDisabled(true);
361 361 self.cm.setOption("readOnly", true);
362 362 var postData = {
363 363 'text': text,
364 364 'changeset_status': status,
365 365 'comment_type': commentType,
366 366 'draft': isDraft,
367 367 'commit_ids': commitIds,
368 368 'csrf_token': CSRF_TOKEN
369 369 };
370 370
371 371 var submitSuccessCallback = function(o) {
372 372 location.reload(true);
373 373 };
374 374 var submitFailCallback = function(){
375 375 self.resetCommentFormState(text)
376 376 };
377 377 self.submitAjaxPOST(
378 378 self.submitUrl, postData, submitSuccessCallback, submitFailCallback);
379 379 });
380 380 % endif
381 381
382 382 </script>
383 383 % else:
384 384 ## form state when not logged in
385 385 <div class="comment-form ac">
386 386
387 387 <div class="comment-area">
388 388 <div class="comment-area-header">
389 389 <ul class="nav-links clearfix">
390 390 <li class="active">
391 391 <a class="disabled" href="#edit-btn" disabled="disabled" onclick="return false">${_('Write')}</a>
392 392 </li>
393 393 <li class="">
394 394 <a class="disabled" href="#preview-btn" disabled="disabled" onclick="return false">${_('Preview')}</a>
395 395 </li>
396 396 </ul>
397 397 </div>
398 398
399 399 <div class="comment-area-write" style="display: block;">
400 400 <div id="edit-container">
401 401 <div style="padding: 20px 0px 0px 0;">
402 402 ${_('You need to be logged in to leave comments.')}
403 403 <a href="${h.route_path('login', _query={'came_from': h.current_route_path(request)})}">${_('Login now')}</a>
404 404 </div>
405 405 </div>
406 406 <div id="preview-container" class="clearfix" style="display: none;">
407 407 <div id="preview-box" class="preview-box"></div>
408 408 </div>
409 409 </div>
410 410
411 411 <div class="comment-area-footer">
412 412 <div class="toolbar">
413 413 <div class="toolbar-text">
414 414 </div>
415 415 </div>
416 416 </div>
417 417 </div>
418 418
419 419 <div class="comment-footer">
420 420 </div>
421 421
422 422 </div>
423 423 % endif
424 424
425 425 <script type="text/javascript">
426 426 bindToggleButtons();
427 427 </script>
428 428 </div>
429 429 </%def>
430 430
431 431
432 432 <%def name="comment_form(form_type, form_id='', lineno_id='{1}', review_statuses=None, form_extras=None)">
433 433
434 434 ## comment injected based on assumption that user is logged in
435 435 <form ${('id="{}"'.format(form_id) if form_id else '') |n} action="#" method="GET">
436 436
437 437 <div class="comment-area">
438 438 <div class="comment-area-header">
439 439 <div class="pull-left">
440 440 <ul class="nav-links clearfix">
441 441 <li class="active">
442 442 <a href="#edit-btn" tabindex="-1" id="edit-btn_${lineno_id}">${_('Write')}</a>
443 443 </li>
444 444 <li class="">
445 445 <a href="#preview-btn" tabindex="-1" id="preview-btn_${lineno_id}">${_('Preview')}</a>
446 446 </li>
447 447 </ul>
448 448 </div>
449 449 <div class="pull-right">
450 450 <span class="comment-area-text">${_('Mark as')}:</span>
451 451 <select class="comment-type" id="comment_type_${lineno_id}" name="comment_type">
452 452 % for val in c.visual.comment_types:
453 453 <option value="${val}">${val.upper()}</option>
454 454 % endfor
455 455 </select>
456 456 </div>
457 457 </div>
458 458
459 459 <div class="comment-area-write" style="display: block;">
460 460 <div id="edit-container_${lineno_id}" style="margin-top: -1px">
461 461 <textarea id="text_${lineno_id}" name="text" class="comment-block-ta ac-input"></textarea>
462 462 </div>
463 463 <div id="preview-container_${lineno_id}" class="clearfix" style="display: none;">
464 464 <div id="preview-box_${lineno_id}" class="preview-box"></div>
465 465 </div>
466 466 </div>
467 467
468 468 <div class="comment-area-footer comment-attachment-uploader">
469 469 <div class="toolbar">
470 470
471 471 <div class="comment-attachment-text">
472 472 <div class="dropzone-text">
473 473 ${_("Drag'n Drop files here or")} <span class="link pick-attachment">${_('Choose your files')}</span>.<br>
474 474 </div>
475 475 <div class="dropzone-upload" style="display:none">
476 476 <i class="icon-spin animate-spin"></i> ${_('uploading...')}
477 477 </div>
478 478 </div>
479 479
480 480 ## comments dropzone template, empty on purpose
481 481 <div style="display: none" class="comment-attachment-uploader-template">
482 482 <div class="dz-file-preview" style="margin: 0">
483 483 <div class="dz-error-message"></div>
484 484 </div>
485 485 </div>
486 486
487 487 </div>
488 488 </div>
489 489 </div>
490 490
491 491 <div class="comment-footer">
492 492
493 493 ## inject extra inputs into the form
494 494 % if form_extras and isinstance(form_extras, (list, tuple)):
495 495 <div id="comment_form_extras">
496 496 % for form_ex_el in form_extras:
497 497 ${form_ex_el|n}
498 498 % endfor
499 499 </div>
500 500 % endif
501 501
502 502 <div class="action-buttons">
503 503 % if form_type != 'inline':
504 504 <div class="action-buttons-extra"></div>
505 505 % endif
506 506
507 507 <input class="btn btn-success comment-button-input submit-comment-action" id="save_${lineno_id}" name="save" type="submit" value="${_('Add comment')}" data-is-draft=false onclick="$(this).addClass('submitter')">
508 508
509 509 % if form_type == 'inline':
510 510 % if c.rhodecode_edition_id == 'EE':
511 511 ## Disable the button for CE, the "real" validation is in the backend code anyway
512 512 <input class="btn btn-draft comment-button-input submit-draft-action" id="save_draft_${lineno_id}" name="save_draft" type="submit" value="${_('Add draft')}" data-is-draft=true onclick="$(this).addClass('submitter')">
513 513 % else:
514 514 <input class="btn btn-draft comment-button-input submit-draft-action disabled" disabled="disabled" type="submit" value="${_('Add draft')}" onclick="return false;" title="Draft comments only available in EE edition of RhodeCode">
515 515 % endif
516 516 % endif
517 517
518 518 % if review_statuses:
519 519 <div class="comment-status-box">
520 520 <select id="change_status_${lineno_id}" name="changeset_status">
521 521 <option></option> ## Placeholder
522 522 % for status, lbl in review_statuses:
523 523 <option value="${status}" data-status="${status}">${lbl}</option>
524 524 %if is_pull_request and change_status and status in ('approved', 'rejected'):
525 525 <option value="${status}_closed" data-status="${status}">${lbl} & ${_('Closed')}</option>
526 526 %endif
527 527 % endfor
528 528 </select>
529 529 </div>
530 530 % endif
531 531
532 532 ## inline for has a file, and line-number together with cancel hide button.
533 533 % if form_type == 'inline':
534 534 <input type="hidden" name="f_path" value="{0}">
535 535 <input type="hidden" name="line" value="${lineno_id}">
536 536 <span style="opacity: 0.7" class="cursor-pointer cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
537 537 ${_('dismiss')}
538 538 </span>
539 539 % endif
540 540 </div>
541 541
542 542 <div class="toolbar-text">
543 543 <% renderer_url = '<a href="%s">%s</a>' % (h.route_url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper()) %>
544 544 <span>${_('{} is supported.').format(renderer_url)|n}
545 545
546 546 <i class="icon-info-circled tooltip-hovercard"
547 547 data-hovercard-alt="ALT"
548 548 data-hovercard-url="javascript:commentHelp('${c.visual.default_renderer.upper()}')"
549 549 data-comment-json-b64='${h.b64(h.str_json({}))}'></i>
550 550 </span>
551 551 </div>
552 552 </div>
553 553
554 554 </form>
555 555
556 556 </%def> No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now