##// END OF EJS Templates
gists: cleanup UI and make the gist access id use monospace
dan -
r4193:e6e77c6a stable
parent child Browse files
Show More
@@ -1,391 +1,391 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 import mock
22 22 import pytest
23 23
24 24 from rhodecode.lib import helpers as h
25 25 from rhodecode.model.db import User, Gist
26 26 from rhodecode.model.gist import GistModel
27 27 from rhodecode.model.meta import Session
28 28 from rhodecode.tests import (
29 29 TEST_USER_ADMIN_LOGIN, TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS,
30 30 TestController, assert_session_flash)
31 31
32 32
33 33 def route_path(name, params=None, **kwargs):
34 34 import urllib
35 35 from rhodecode.apps._base import ADMIN_PREFIX
36 36
37 37 base_url = {
38 38 'gists_show': ADMIN_PREFIX + '/gists',
39 39 'gists_new': ADMIN_PREFIX + '/gists/new',
40 40 'gists_create': ADMIN_PREFIX + '/gists/create',
41 41 'gist_show': ADMIN_PREFIX + '/gists/{gist_id}',
42 42 'gist_delete': ADMIN_PREFIX + '/gists/{gist_id}/delete',
43 43 'gist_edit': ADMIN_PREFIX + '/gists/{gist_id}/edit',
44 44 'gist_edit_check_revision': ADMIN_PREFIX + '/gists/{gist_id}/edit/check_revision',
45 45 'gist_update': ADMIN_PREFIX + '/gists/{gist_id}/update',
46 46 'gist_show_rev': ADMIN_PREFIX + '/gists/{gist_id}/{revision}',
47 47 'gist_show_formatted': ADMIN_PREFIX + '/gists/{gist_id}/{revision}/{format}',
48 48 'gist_show_formatted_path': ADMIN_PREFIX + '/gists/{gist_id}/{revision}/{format}/{f_path}',
49 49
50 50 }[name].format(**kwargs)
51 51
52 52 if params:
53 53 base_url = '{}?{}'.format(base_url, urllib.urlencode(params))
54 54 return base_url
55 55
56 56
57 57 class GistUtility(object):
58 58
59 59 def __init__(self):
60 60 self._gist_ids = []
61 61
62 62 def __call__(
63 63 self, f_name, content='some gist', lifetime=-1,
64 64 description='gist-desc', gist_type='public',
65 65 acl_level=Gist.GIST_PUBLIC, owner=TEST_USER_ADMIN_LOGIN):
66 66 gist_mapping = {
67 67 f_name: {'content': content}
68 68 }
69 69 user = User.get_by_username(owner)
70 70 gist = GistModel().create(
71 71 description, owner=user, gist_mapping=gist_mapping,
72 72 gist_type=gist_type, lifetime=lifetime, gist_acl_level=acl_level)
73 73 Session().commit()
74 74 self._gist_ids.append(gist.gist_id)
75 75 return gist
76 76
77 77 def cleanup(self):
78 78 for gist_id in self._gist_ids:
79 79 gist = Gist.get(gist_id)
80 80 if gist:
81 81 Session().delete(gist)
82 82
83 83 Session().commit()
84 84
85 85
86 86 @pytest.fixture()
87 87 def create_gist(request):
88 88 gist_utility = GistUtility()
89 89 request.addfinalizer(gist_utility.cleanup)
90 90 return gist_utility
91 91
92 92
93 93 class TestGistsController(TestController):
94 94
95 95 def test_index_empty(self, create_gist):
96 96 self.log_user()
97 97 response = self.app.get(route_path('gists_show'))
98 98 response.mustcontain('data: [],')
99 99
100 100 def test_index(self, create_gist):
101 101 self.log_user()
102 102 g1 = create_gist('gist1')
103 103 g2 = create_gist('gist2', lifetime=1400)
104 104 g3 = create_gist('gist3', description='gist3-desc')
105 105 g4 = create_gist('gist4', gist_type='private').gist_access_id
106 106 response = self.app.get(route_path('gists_show'))
107 107
108 response.mustcontain('gist: %s' % g1.gist_access_id)
109 response.mustcontain('gist: %s' % g2.gist_access_id)
110 response.mustcontain('gist: %s' % g3.gist_access_id)
108 response.mustcontain(g1.gist_access_id)
109 response.mustcontain(g2.gist_access_id)
110 response.mustcontain(g3.gist_access_id)
111 111 response.mustcontain('gist3-desc')
112 response.mustcontain(no=['gist: %s' % g4])
112 response.mustcontain(no=[g4])
113 113
114 114 # Expiration information should be visible
115 115 expires_tag = '%s' % h.age_component(
116 116 h.time_to_utcdatetime(g2.gist_expires))
117 117 response.mustcontain(expires_tag.replace('"', '\\"'))
118 118
119 119 def test_index_private_gists(self, create_gist):
120 120 self.log_user()
121 121 gist = create_gist('gist5', gist_type='private')
122 122 response = self.app.get(route_path('gists_show', params=dict(private=1)))
123 123
124 124 # and privates
125 response.mustcontain('gist: %s' % gist.gist_access_id)
125 response.mustcontain(gist.gist_access_id)
126 126
127 127 def test_index_show_all(self, create_gist):
128 128 self.log_user()
129 129 create_gist('gist1')
130 130 create_gist('gist2', lifetime=1400)
131 131 create_gist('gist3', description='gist3-desc')
132 132 create_gist('gist4', gist_type='private')
133 133
134 134 response = self.app.get(route_path('gists_show', params=dict(all=1)))
135 135
136 136 assert len(GistModel.get_all()) == 4
137 137 # and privates
138 138 for gist in GistModel.get_all():
139 response.mustcontain('gist: %s' % gist.gist_access_id)
139 response.mustcontain(gist.gist_access_id)
140 140
141 141 def test_index_show_all_hidden_from_regular(self, create_gist):
142 142 self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
143 143 create_gist('gist2', gist_type='private')
144 144 create_gist('gist3', gist_type='private')
145 145 create_gist('gist4', gist_type='private')
146 146
147 147 response = self.app.get(route_path('gists_show', params=dict(all=1)))
148 148
149 149 assert len(GistModel.get_all()) == 3
150 150 # since we don't have access to private in this view, we
151 151 # should see nothing
152 152 for gist in GistModel.get_all():
153 response.mustcontain(no=['gist: %s' % gist.gist_access_id])
153 response.mustcontain(no=[gist.gist_access_id])
154 154
155 155 def test_create(self):
156 156 self.log_user()
157 157 response = self.app.post(
158 158 route_path('gists_create'),
159 159 params={'lifetime': -1,
160 160 'content': 'gist test',
161 161 'filename': 'foo',
162 162 'gist_type': 'public',
163 163 'gist_acl_level': Gist.ACL_LEVEL_PUBLIC,
164 164 'csrf_token': self.csrf_token},
165 165 status=302)
166 166 response = response.follow()
167 167 response.mustcontain('added file: foo')
168 168 response.mustcontain('gist test')
169 169
170 170 def test_create_with_path_with_dirs(self):
171 171 self.log_user()
172 172 response = self.app.post(
173 173 route_path('gists_create'),
174 174 params={'lifetime': -1,
175 175 'content': 'gist test',
176 176 'filename': '/home/foo',
177 177 'gist_type': 'public',
178 178 'gist_acl_level': Gist.ACL_LEVEL_PUBLIC,
179 179 'csrf_token': self.csrf_token},
180 180 status=200)
181 181 response.mustcontain('Filename /home/foo cannot be inside a directory')
182 182
183 183 def test_access_expired_gist(self, create_gist):
184 184 self.log_user()
185 185 gist = create_gist('never-see-me')
186 186 gist.gist_expires = 0 # 1970
187 187 Session().add(gist)
188 188 Session().commit()
189 189
190 190 self.app.get(route_path('gist_show', gist_id=gist.gist_access_id),
191 191 status=404)
192 192
193 193 def test_create_private(self):
194 194 self.log_user()
195 195 response = self.app.post(
196 196 route_path('gists_create'),
197 197 params={'lifetime': -1,
198 198 'content': 'private gist test',
199 199 'filename': 'private-foo',
200 200 'gist_type': 'private',
201 201 'gist_acl_level': Gist.ACL_LEVEL_PUBLIC,
202 202 'csrf_token': self.csrf_token},
203 203 status=302)
204 204 response = response.follow()
205 205 response.mustcontain('added file: private-foo<')
206 206 response.mustcontain('private gist test')
207 207 response.mustcontain('Private Gist')
208 208 # Make sure private gists are not indexed by robots
209 209 response.mustcontain(
210 210 '<meta name="robots" content="noindex, nofollow">')
211 211
212 212 def test_create_private_acl_private(self):
213 213 self.log_user()
214 214 response = self.app.post(
215 215 route_path('gists_create'),
216 216 params={'lifetime': -1,
217 217 'content': 'private gist test',
218 218 'filename': 'private-foo',
219 219 'gist_type': 'private',
220 220 'gist_acl_level': Gist.ACL_LEVEL_PRIVATE,
221 221 'csrf_token': self.csrf_token},
222 222 status=302)
223 223 response = response.follow()
224 224 response.mustcontain('added file: private-foo<')
225 225 response.mustcontain('private gist test')
226 226 response.mustcontain('Private Gist')
227 227 # Make sure private gists are not indexed by robots
228 228 response.mustcontain(
229 229 '<meta name="robots" content="noindex, nofollow">')
230 230
231 231 def test_create_with_description(self):
232 232 self.log_user()
233 233 response = self.app.post(
234 234 route_path('gists_create'),
235 235 params={'lifetime': -1,
236 236 'content': 'gist test',
237 237 'filename': 'foo-desc',
238 238 'description': 'gist-desc',
239 239 'gist_type': 'public',
240 240 'gist_acl_level': Gist.ACL_LEVEL_PUBLIC,
241 241 'csrf_token': self.csrf_token},
242 242 status=302)
243 243 response = response.follow()
244 244 response.mustcontain('added file: foo-desc')
245 245 response.mustcontain('gist test')
246 246 response.mustcontain('gist-desc')
247 247
248 248 def test_create_public_with_anonymous_access(self):
249 249 self.log_user()
250 250 params = {
251 251 'lifetime': -1,
252 252 'content': 'gist test',
253 253 'filename': 'foo-desc',
254 254 'description': 'gist-desc',
255 255 'gist_type': 'public',
256 256 'gist_acl_level': Gist.ACL_LEVEL_PUBLIC,
257 257 'csrf_token': self.csrf_token
258 258 }
259 259 response = self.app.post(
260 260 route_path('gists_create'), params=params, status=302)
261 261 self.logout_user()
262 262 response = response.follow()
263 263 response.mustcontain('added file: foo-desc')
264 264 response.mustcontain('gist test')
265 265 response.mustcontain('gist-desc')
266 266
267 267 def test_new(self):
268 268 self.log_user()
269 269 self.app.get(route_path('gists_new'))
270 270
271 271 def test_delete(self, create_gist):
272 272 self.log_user()
273 273 gist = create_gist('delete-me')
274 274 response = self.app.post(
275 275 route_path('gist_delete', gist_id=gist.gist_id),
276 276 params={'csrf_token': self.csrf_token})
277 277 assert_session_flash(response, 'Deleted gist %s' % gist.gist_id)
278 278
279 279 def test_delete_normal_user_his_gist(self, create_gist):
280 280 self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
281 281 gist = create_gist('delete-me', owner=TEST_USER_REGULAR_LOGIN)
282 282
283 283 response = self.app.post(
284 284 route_path('gist_delete', gist_id=gist.gist_id),
285 285 params={'csrf_token': self.csrf_token})
286 286 assert_session_flash(response, 'Deleted gist %s' % gist.gist_id)
287 287
288 288 def test_delete_normal_user_not_his_own_gist(self, create_gist):
289 289 self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
290 290 gist = create_gist('delete-me-2')
291 291
292 292 self.app.post(
293 293 route_path('gist_delete', gist_id=gist.gist_id),
294 294 params={'csrf_token': self.csrf_token}, status=404)
295 295
296 296 def test_show(self, create_gist):
297 297 gist = create_gist('gist-show-me')
298 298 response = self.app.get(route_path('gist_show', gist_id=gist.gist_access_id))
299 299
300 300 response.mustcontain('added file: gist-show-me<')
301 301
302 302 assert_response = response.assert_response()
303 303 assert_response.element_equals_to(
304 304 'div.rc-user span.user',
305 305 '<a href="/_profiles/test_admin">test_admin</a></span>')
306 306
307 307 response.mustcontain('gist-desc')
308 308
309 309 def test_show_without_hg(self, create_gist):
310 310 with mock.patch(
311 311 'rhodecode.lib.vcs.settings.ALIASES', ['git']):
312 312 gist = create_gist('gist-show-me-again')
313 313 self.app.get(
314 314 route_path('gist_show', gist_id=gist.gist_access_id), status=200)
315 315
316 316 def test_show_acl_private(self, create_gist):
317 317 gist = create_gist('gist-show-me-only-when-im-logged-in',
318 318 acl_level=Gist.ACL_LEVEL_PRIVATE)
319 319 self.app.get(
320 320 route_path('gist_show', gist_id=gist.gist_access_id), status=404)
321 321
322 322 # now we log-in we should see thi gist
323 323 self.log_user()
324 324 response = self.app.get(
325 325 route_path('gist_show', gist_id=gist.gist_access_id))
326 326 response.mustcontain('added file: gist-show-me-only-when-im-logged-in')
327 327
328 328 assert_response = response.assert_response()
329 329 assert_response.element_equals_to(
330 330 'div.rc-user span.user',
331 331 '<a href="/_profiles/test_admin">test_admin</a></span>')
332 332 response.mustcontain('gist-desc')
333 333
334 334 def test_show_as_raw(self, create_gist):
335 335 gist = create_gist('gist-show-me', content='GIST CONTENT')
336 336 response = self.app.get(
337 337 route_path('gist_show_formatted',
338 338 gist_id=gist.gist_access_id, revision='tip',
339 339 format='raw'))
340 340 assert response.body == 'GIST CONTENT'
341 341
342 342 def test_show_as_raw_individual_file(self, create_gist):
343 343 gist = create_gist('gist-show-me-raw', content='GIST BODY')
344 344 response = self.app.get(
345 345 route_path('gist_show_formatted_path',
346 346 gist_id=gist.gist_access_id, format='raw',
347 347 revision='tip', f_path='gist-show-me-raw'))
348 348 assert response.body == 'GIST BODY'
349 349
350 350 def test_edit_page(self, create_gist):
351 351 self.log_user()
352 352 gist = create_gist('gist-for-edit', content='GIST EDIT BODY')
353 353 response = self.app.get(route_path('gist_edit', gist_id=gist.gist_access_id))
354 354 response.mustcontain('GIST EDIT BODY')
355 355
356 356 def test_edit_page_non_logged_user(self, create_gist):
357 357 gist = create_gist('gist-for-edit', content='GIST EDIT BODY')
358 358 self.app.get(route_path('gist_edit', gist_id=gist.gist_access_id),
359 359 status=302)
360 360
361 361 def test_edit_normal_user_his_gist(self, create_gist):
362 362 self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
363 363 gist = create_gist('gist-for-edit', owner=TEST_USER_REGULAR_LOGIN)
364 364 self.app.get(route_path('gist_edit', gist_id=gist.gist_access_id,
365 365 status=200))
366 366
367 367 def test_edit_normal_user_not_his_own_gist(self, create_gist):
368 368 self.log_user(TEST_USER_REGULAR_LOGIN, TEST_USER_REGULAR_PASS)
369 369 gist = create_gist('delete-me')
370 370 self.app.get(route_path('gist_edit', gist_id=gist.gist_access_id),
371 371 status=404)
372 372
373 373 def test_user_first_name_is_escaped(self, user_util, create_gist):
374 374 xss_atack_string = '"><script>alert(\'First Name\')</script>'
375 375 xss_escaped_string = h.html_escape(h.escape(xss_atack_string))
376 376 password = 'test'
377 377 user = user_util.create_user(
378 378 firstname=xss_atack_string, password=password)
379 379 create_gist('gist', gist_type='public', owner=user.username)
380 380 response = self.app.get(route_path('gists_show'))
381 381 response.mustcontain(xss_escaped_string)
382 382
383 383 def test_user_last_name_is_escaped(self, user_util, create_gist):
384 384 xss_atack_string = '"><script>alert(\'Last Name\')</script>'
385 385 xss_escaped_string = h.html_escape(h.escape(xss_atack_string))
386 386 password = 'test'
387 387 user = user_util.create_user(
388 388 lastname=xss_atack_string, password=password)
389 389 create_gist('gist', gist_type='public', owner=user.username)
390 390 response = self.app.get(route_path('gists_show'))
391 391 response.mustcontain(xss_escaped_string)
@@ -1,553 +1,560 b''
1 1
2 2 // tables.less
3 3 // For use in RhodeCode application tables;
4 4 // see style guide documentation for guidelines.
5 5
6 6 // TABLES
7 7
8 8 .rctable,
9 9 table.rctable,
10 10 table.dataTable {
11 11 clear:both;
12 12 width: 100%;
13 13 margin: 0 auto @padding;
14 14 padding: 0;
15 15 vertical-align: baseline;
16 16 line-height:1.5em;
17 17 border: none;
18 18 outline: none;
19 19 border-collapse: collapse;
20 20 border-spacing: 0;
21 21 color: @grey2;
22 22
23 23 b {
24 24 font-weight: normal;
25 25 }
26 26
27 27 em {
28 28 font-weight: bold;
29 29 font-style: normal;
30 30 }
31 31
32 32 .td-user {
33 33 .rc-user {
34 34 white-space: nowrap;
35 35 }
36 36 }
37 37
38 38 .td-email {
39 39 white-space: nowrap;
40 40 }
41 41
42 42 th,
43 43 td {
44 44 height: auto;
45 45 max-width: 20%;
46 46 padding: .65em 0 .65em 1em;
47 47 vertical-align: middle;
48 48 border-bottom: @border-thickness solid @grey5;
49 49 white-space: normal;
50 50
51 51 &.td-radio,
52 52 &.td-checkbox {
53 53 padding-right: 0;
54 54 text-align: center;
55 55
56 56 input {
57 57 margin: 0 1em;
58 58 }
59 59 }
60 60
61 61 &.truncate-wrap {
62 62 white-space: nowrap !important;
63 63 }
64 64
65 65 pre {
66 66 margin: 0;
67 67 }
68 68
69 69 .show_more {
70 70 height: inherit;
71 71 }
72 72 }
73 73
74 74 .expired td {
75 75 background-color: @grey7;
76 76 }
77 77 .inactive td {
78 78 background-color: @grey6;
79 79 }
80 80 th {
81 81 text-align: left;
82 82 font-weight: @text-semibold-weight;
83 83 font-family: @text-semibold;
84 84 }
85 85
86 86 .hl {
87 87 td {
88 88 background-color: lighten(@alert4,25%);
89 89 }
90 90 }
91 91
92 92 // Special Data Cell Types
93 93 // See style guide for desciptions and examples.
94 94
95 95 td {
96 96
97 97 &.user {
98 98 padding-left: 1em;
99 99 }
100 100
101 101 &.td-rss {
102 102 width: 20px;
103 103 min-width: 0;
104 104 margin: 0;
105 105 }
106 106
107 107 &.quick_repo_menu {
108 108 width: 15px;
109 109 text-align: center;
110 110
111 111 &:hover {
112 112 background-color: @grey5;
113 113 }
114 114 }
115 115
116 116 &.td-icon {
117 117 min-width: 20px;
118 118 width: 20px;
119 119 }
120 120
121 121 &.td-hash {
122 122 min-width: 80px;
123 123 width: 200px;
124 124
125 125 .obsolete {
126 126 text-decoration: line-through;
127 127 color: lighten(@grey2,25%);
128 128 }
129 129 }
130 130
131 131 &.td-sha {
132 132 white-space: nowrap;
133 133 }
134 134
135 135 &.td-graphbox {
136 136 width: 100px;
137 137 max-width: 100px;
138 138 min-width: 100px;
139 139 }
140 140
141 141 &.td-time {
142 142 width: 160px;
143 143 white-space: nowrap;
144 144 }
145 145
146 146 &.annotate{
147 147 padding-right: 0;
148 148
149 149 div.annotatediv{
150 150 margin: 0 0.7em;
151 151 }
152 152 }
153 153
154 154 &.tags-col {
155 155 padding-right: 0;
156 156 }
157 157
158 158 &.td-description {
159 159 min-width: 350px;
160 160
161 161 &.truncate, .truncate-wrap {
162 162 white-space: nowrap;
163 163 overflow: hidden;
164 164 text-overflow: ellipsis;
165 165 max-width: 350px;
166 166 }
167 167 }
168 168
169 169 &.td-grid-name {
170 170 white-space: nowrap;
171 171 min-width: 300px;
172 172 }
173 173
174 174 &.td-componentname {
175 175 white-space: nowrap;
176 176 }
177 177
178 178 &.td-name {
179 179
180 180 }
181 181
182 182 &.td-journalaction {
183 183 min-width: 300px;
184 184
185 185 .journal_action_params {
186 186 // waiting for feedback
187 187 }
188 188 }
189 189
190 190 &.td-active {
191 191 padding-left: .65em;
192 192 }
193 193
194 194 &.td-issue-tracker-name {
195 195 width: 180px;
196 196 input {
197 197 width: 180px;
198 198 }
199 199
200 200 }
201 201
202 202 &.td-issue-tracker-regex {
203 203 white-space: nowrap;
204 204
205 205 min-width: 300px;
206 206 input {
207 207 min-width: 300px;
208 208 }
209 209
210 210 }
211 211
212 212 &.td-url {
213 213 white-space: nowrap;
214 214 }
215 215
216 216 &.td-comments {
217 217 min-width: 3em;
218 218 }
219 219
220 220 &.td-buttons {
221 221 padding: .3em 0;
222 222 }
223 223 &.td-align-top {
224 224 vertical-align: text-top
225 225 }
226 226 &.td-action {
227 227 // this is for the remove/delete/edit buttons
228 228 padding-right: 0;
229 229 min-width: 95px;
230 230 text-transform: capitalize;
231 231
232 232 i {
233 233 display: none;
234 234 }
235 235 }
236 236
237 237 // TODO: lisa: this needs to be cleaned up with the buttons
238 238 .grid_edit,
239 239 .grid_delete {
240 240 display: inline-block;
241 241 margin: 0 @padding/3 0 0;
242 242 font-family: @text-light;
243 243
244 244 i {
245 245 display: none;
246 246 }
247 247 }
248 248
249 249 .grid_edit + .grid_delete {
250 250 border-left: @border-thickness solid @grey5;
251 251 padding-left: @padding/2;
252 252 }
253 253
254 254 &.td-compare {
255 255
256 256 input {
257 257 margin-right: 1em;
258 258 }
259 259
260 260 .compare-radio-button {
261 261 margin: 0 1em 0 0;
262 262 }
263 263
264 264
265 265 }
266 266
267 267 &.td-tags {
268 268 padding: .5em 1em .5em 0;
269 269 width: 140px;
270 270
271 271 .tag {
272 272 margin: 1px;
273 273 float: left;
274 274 }
275 275 }
276 276
277 277 .icon-svn, .icon-hg, .icon-git {
278 278 font-size: 1.4em;
279 279 }
280 280
281 281 &.collapse_commit,
282 282 &.expand_commit {
283 283 padding-right: 0;
284 284 padding-left: 1em;
285 285 cursor: pointer;
286 286 width: 20px;
287 287 }
288 288 }
289 289
290 290 .perm_admin_row {
291 291 color: @grey4;
292 292 background-color: @grey6;
293 293 }
294 294
295 295 .noborder {
296 296 border: none;
297 297
298 298 td {
299 299 border: none;
300 300 }
301 301 }
302 302 }
303 303 .rctable.audit-log {
304 304 td {
305 305 vertical-align: top;
306 306 }
307 307 }
308 308
309 309 // TRUNCATING
310 310 // TODO: lisaq: should this possibly be moved out of tables.less?
311 311 // for truncated text
312 312 // used inside of table cells and in code block headers
313 313 .truncate-wrap {
314 314 white-space: nowrap !important;
315 315
316 316 //truncated text
317 317 .truncate {
318 318 max-width: 450px;
319 319 width: 300px;
320 320 overflow: hidden;
321 321 text-overflow: ellipsis;
322 322 -o-text-overflow: ellipsis;
323 323 -ms-text-overflow: ellipsis;
324 324
325 325 &.autoexpand {
326 326 width: 120px;
327 327 margin-right: 200px;
328 328 }
329 329 }
330 330 &:hover .truncate.autoexpand {
331 331 overflow: visible;
332 332 }
333 333
334 334 .tags-truncate {
335 335 width: 150px;
336 336 height: 22px;
337 337 overflow: hidden;
338 338
339 339 .tag {
340 340 display: inline-block;
341 341 }
342 342
343 343 &.truncate {
344 344 height: 22px;
345 345 max-height:2em;
346 346 width: 140px;
347 347 }
348 348 }
349 349 }
350 350
351 351 .apikeys_wrap {
352 352 margin-bottom: @padding;
353 353
354 354 table.rctable td:first-child {
355 355 width: 340px;
356 356 }
357 357 }
358 358
359 359
360 360
361 361 // SPECIAL CASES
362 362
363 363 // Repository Followers
364 364 table.rctable.followers_data {
365 365 width: 75%;
366 366 margin: 0;
367 367 }
368 368
369 369 // Repository List
370 370 // Group Members List
371 371 table.rctable.group_members,
372 372 table#repo_list_table {
373 373 min-width: 600px;
374 374 }
375 375
376 376 #no_grid_data {
377 377 text-align: center;
378 378 }
379 379
380 380 #grid_data_loading {
381 381 text-align: center;
382 382 font-weight: 600;
383 383 font-size: 16px;
384 384 padding: 80px 20px;
385 385 }
386 386
387 387 // Keyboard mappings
388 388 table.keyboard-mappings {
389 389 th {
390 390 text-align: left;
391 391 font-weight: @text-semibold-weight;
392 392 font-family: @text-semibold;
393 393 }
394 394 }
395 395
396 396 // Branches, Tags, and Bookmarks
397 397 #obj_list_table.dataTable {
398 398 td.td-time {
399 399 padding-right: 1em;
400 400 }
401 401 }
402 402
403 403 // User Admin
404 404 .rctable.useremails,
405 405 .rctable.account_emails {
406 406 .tag,
407 407 .btn {
408 408 float: right;
409 409 }
410 410 .btn { //to line up with tags
411 411 margin-right: 1.65em;
412 412 }
413 413 }
414 414
415 415 // User List
416 416 #user_list_table {
417 417
418 418 td.td-user {
419 419 min-width: 100px;
420 420 }
421 421 }
422 422
423 423 // Pull Request List Table
424 424 #pull_request_list_table.dataTable {
425 425
426 426 //TODO: lisa: This needs to be removed once the description is adjusted
427 427 // for using an expand_commit button (see issue 765)
428 428 td {
429 429 vertical-align: middle;
430 430 }
431 431 }
432 432
433 433 // Settings (no border)
434 434 table.rctable.dl-settings {
435 435 td {
436 436 border: none;
437 437 vertical-align: baseline;
438 438 }
439 439 }
440 440
441 441
442 442 // Statistics
443 443 table.trending_language_tbl {
444 444 width: 100%;
445 445 line-height: 1em;
446 446
447 447 td div {
448 448 overflow: visible;
449 449 }
450 450 }
451 451
452 452 .trending_language_tbl, .trending_language_tbl td {
453 453 border: 0;
454 454 margin: 0;
455 455 padding: 0;
456 456 background: transparent;
457 457 }
458 458
459 459 .trending_language_tbl, .trending_language_tbl tr {
460 460 border-spacing: 0 3px;
461 461 }
462 462
463 463 .trending_language {
464 464 position: relative;
465 465 overflow: hidden;
466 466 color: @text-color;
467 467 width: 400px;
468 468
469 469 .lang-bar {
470 470 z-index: 1;
471 471 overflow: hidden;
472 472 background-color: @rcblue;
473 473 color: #FFF;
474 474 text-decoration: none;
475 475 }
476 476
477 477 }
478 478
479 479 // Changesets
480 480 #changesets.rctable {
481 481 th {
482 482 padding: 0 1em 0.65em 0;
483 483 }
484 484
485 485 // td must be fixed height for graph
486 486 td {
487 487 height: 32px;
488 488 padding: 0 1em 0 0;
489 489 vertical-align: middle;
490 490 white-space: nowrap;
491 491
492 492 &.td-description {
493 493 white-space: normal;
494 494 }
495 495
496 496 &.expand_commit {
497 497 padding-right: 0;
498 498 cursor: pointer;
499 499 width: 20px;
500 500 }
501 501 }
502 502 }
503 503
504 504 // Compare
505 505 table.compare_view_commits {
506 506 margin-top: @space;
507 507
508 508 td.td-time {
509 509 padding-left: .5em;
510 510 }
511 511
512 512 // special case to not show hover actions on hidden indicator
513 513 tr.compare_select_hidden:hover {
514 514 cursor: inherit;
515 515
516 516 td {
517 517 background-color: inherit;
518 518 }
519 519 }
520 520
521 521 tr:hover {
522 522 cursor: pointer;
523 523
524 524 td {
525 525 background-color: lighten(@alert4,25%);
526 526 }
527 527 }
528 528
529 529
530 530 }
531 531
532 532 .file_history {
533 533 td.td-actions {
534 534 text-align: right;
535 535 }
536 536 }
537 537
538 538
539 539 // Gist List
540 540 #gist_list_table {
541 541 td {
542 542 vertical-align: middle;
543 543
544 544 div{
545 545 display: inline-block;
546 546 vertical-align: middle;
547 547 }
548 548
549 549 img{
550 550 vertical-align: middle;
551 551 }
552
553 &.td-expire {
554 width: 200px;
555 }
556 &.td-gist-type {
557 width: 100px;
552 558 }
553 559 }
560 }
@@ -1,147 +1,147 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="/base/base.mako"/>
3 3
4 4 <%def name="title()">
5 5 %if c.show_private:
6 6 ${_('Private Gists for user {}').format(c.rhodecode_user.username)}
7 7 %elif c.show_public:
8 8 ${_('Public Gists for user {}').format(c.rhodecode_user.username)}
9 9 %else:
10 10 ${_('Public Gists')}
11 11 %endif
12 12 %if c.rhodecode_name:
13 13 &middot; ${h.branding(c.rhodecode_name)}
14 14 %endif
15 15 </%def>
16 16
17 17 <%def name="breadcrumbs_links()"></%def>
18 18
19 19 <%def name="menu_bar_nav()">
20 20 ${self.menu_items(active='gists')}
21 21 </%def>
22 22
23 23 <%def name="main()">
24 24
25 25 <div class="box">
26 26 <div class="title">
27 27
28 28 <ul class="button-links">
29 29 % if c.is_super_admin:
30 30 <li class="btn ${h.is_active('all', c.active)}"><a href="${h.route_path('gists_show', _query={'all': 1})}">${_('All gists')}</a></li>
31 31 %endif
32 32 <li class="btn ${h.is_active('public', c.active)}"><a href="${h.route_path('gists_show')}">${_('All public')}</a></li>
33 33 %if c.rhodecode_user.username != h.DEFAULT_USER:
34 34 <li class="btn ${h.is_active('my_all', c.active)}"><a href="${h.route_path('gists_show', _query={'public':1, 'private': 1})}">${_('My gists')}</a></li>
35 35 <li class="btn ${h.is_active('my_private', c.active)}"><a href="${h.route_path('gists_show', _query={'private': 1})}">${_('My private')}</a></li>
36 36 <li class="btn ${h.is_active('my_public', c.active)}"><a href="${h.route_path('gists_show', _query={'public': 1})}">${_('My public')}</a></li>
37 37 %endif
38 38 </ul>
39 39
40 40 % if c.rhodecode_user.username != h.DEFAULT_USER:
41 41 <div class="pull-right">
42 42 <a class="btn btn-primary" href="${h.route_path('gists_new')}" >
43 43 ${_(u'Create New Gist')}
44 44 </a>
45 45 </div>
46 46 % endif
47 47
48 48 <div class="grid-quick-filter">
49 49 <ul class="grid-filter-box">
50 50 <li class="grid-filter-box-icon">
51 51 <i class="icon-search"></i>
52 52 </li>
53 53 <li class="grid-filter-box-input">
54 54 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
55 55 </li>
56 56 </ul>
57 57 </div>
58 58
59 59 </div>
60 60
61 61 <div class="main-content-full-width">
62 62 <div id="repos_list_wrap">
63 63 <table id="gist_list_table" class="display"></table>
64 64 </div>
65 65 </div>
66 66
67 67 </div>
68 68
69 69 <script type="text/javascript">
70 70 $(document).ready(function() {
71 71
72 72 var get_datatable_count = function(){
73 73 var api = $('#gist_list_table').dataTable().api();
74 74 $('#gists_count').text(api.page.info().recordsDisplay);
75 75 };
76 76
77 77
78 78 // custom filter that filters by access_id, description or author
79 79 $.fn.dataTable.ext.search.push(
80 80 function( settings, data, dataIndex ) {
81 81 var query = $('#q_filter').val();
82 82 var author = data[0].strip();
83 83 var access_id = data[2].strip();
84 84 var description = data[3].strip();
85 85
86 86 var query_str = (access_id + " " + author + " " + description).toLowerCase();
87 87
88 88 if(query_str.indexOf(query.toLowerCase()) !== -1){
89 89 return true;
90 90 }
91 91 return false;
92 92 }
93 93 );
94 94
95 95 // gists list
96 96 $('#gist_list_table').DataTable({
97 97 data: ${c.data|n},
98 98 dom: 'rtp',
99 99 pageLength: ${c.visual.dashboard_items},
100 100 order: [[ 4, "desc" ]],
101 101 columns: [
102 102 { data: {"_": "author",
103 103 "sort": "author_raw"}, title: "${_("Author")}", width: "250px", className: "td-user" },
104 104 { data: {"_": "type",
105 "sort": "type"}, title: "${_("Type")}", width: "70px", className: "td-tags" },
105 "sort": "type"}, title: "${_("Type")}", width: "100px", className: "td-gist-type" },
106 106 { data: {"_": "access_id",
107 107 "sort": "access_id"}, title: "${_("Name")}", width:"150px", className: "td-componentname" },
108 108 { data: {"_": "description",
109 109 "sort": "description"}, title: "${_("Description")}", width: "250px", className: "td-description" },
110 110 { data: {"_": "created_on",
111 111 "sort": "created_on_raw"}, title: "${_("Created on")}", className: "td-time" },
112 112 { data: {"_": "expires",
113 "sort": "expires"}, title: "${_("Expires")}", className: "td-exp" }
113 "sort": "expires"}, title: "${_("Expires")}", width: "200px", className: "td-expire" }
114 114 ],
115 115 language: {
116 116 paginate: DEFAULT_GRID_PAGINATION,
117 117 emptyTable: _gettext("No gists available yet.")
118 118 },
119 119 "initComplete": function( settings, json ) {
120 120 timeagoActivate();
121 121 tooltipActivate();
122 122 get_datatable_count();
123 123 }
124 124 });
125 125
126 126 // update the counter when things change
127 127 $('#gist_list_table').on('draw.dt', function() {
128 128 timeagoActivate();
129 129 tooltipActivate();
130 130 get_datatable_count();
131 131 });
132 132
133 133 // filter, filter both grids
134 134 $('#q_filter').on( 'keyup', function () {
135 135 var repo_api = $('#gist_list_table').dataTable().api();
136 136 repo_api
137 137 .draw();
138 138 });
139 139
140 140 // refilter table if page load via back button
141 141 $("#q_filter").trigger('keyup');
142 142
143 143 });
144 144
145 145 </script>
146 146 </%def>
147 147
@@ -1,479 +1,479 b''
1 1 ## DATA TABLE RE USABLE ELEMENTS
2 2 ## usage:
3 3 ## <%namespace name="dt" file="/data_table/_dt_elements.mako"/>
4 4 <%namespace name="base" file="/base/base.mako"/>
5 5
6 6 <%def name="metatags_help()">
7 7 <table>
8 8 <%
9 9 example_tags = [
10 10 ('state','[stable]'),
11 11 ('state','[stale]'),
12 12 ('state','[featured]'),
13 13 ('state','[dev]'),
14 14 ('state','[dead]'),
15 15 ('state','[deprecated]'),
16 16
17 17 ('label','[personal]'),
18 18 ('generic','[v2.0.0]'),
19 19
20 20 ('lang','[lang =&gt; JavaScript]'),
21 21 ('license','[license =&gt; LicenseName]'),
22 22
23 23 ('ref','[requires =&gt; RepoName]'),
24 24 ('ref','[recommends =&gt; GroupName]'),
25 25 ('ref','[conflicts =&gt; SomeName]'),
26 26 ('ref','[base =&gt; SomeName]'),
27 27 ('url','[url =&gt; [linkName](https://rhodecode.com)]'),
28 28 ('see','[see =&gt; http://rhodecode.com]'),
29 29 ]
30 30 %>
31 31 % for tag_type, tag in example_tags:
32 32 <tr>
33 33 <td>${tag|n}</td>
34 34 <td>${h.style_metatag(tag_type, tag)|n}</td>
35 35 </tr>
36 36 % endfor
37 37 </table>
38 38 </%def>
39 39
40 40 <%def name="render_description(description, stylify_metatags)">
41 41 <%
42 42 tags = []
43 43 if stylify_metatags:
44 44 tags, description = h.extract_metatags(description)
45 45 %>
46 46 % for tag_type, tag in tags:
47 47 ${h.style_metatag(tag_type, tag)|n,trim}
48 48 % endfor
49 49 <code style="white-space: pre-wrap">${description}</code>
50 50 </%def>
51 51
52 52 ## REPOSITORY RENDERERS
53 53 <%def name="quick_menu(repo_name)">
54 54 <i class="icon-more"></i>
55 55 <div class="menu_items_container hidden">
56 56 <ul class="menu_items">
57 57 <li>
58 58 <a title="${_('Summary')}" href="${h.route_path('repo_summary',repo_name=repo_name)}">
59 59 <span>${_('Summary')}</span>
60 60 </a>
61 61 </li>
62 62 <li>
63 63 <a title="${_('Commits')}" href="${h.route_path('repo_commits',repo_name=repo_name)}">
64 64 <span>${_('Commits')}</span>
65 65 </a>
66 66 </li>
67 67 <li>
68 68 <a title="${_('Files')}" href="${h.route_path('repo_files:default_commit',repo_name=repo_name)}">
69 69 <span>${_('Files')}</span>
70 70 </a>
71 71 </li>
72 72 <li>
73 73 <a title="${_('Fork')}" href="${h.route_path('repo_fork_new',repo_name=repo_name)}">
74 74 <span>${_('Fork')}</span>
75 75 </a>
76 76 </li>
77 77 </ul>
78 78 </div>
79 79 </%def>
80 80
81 81 <%def name="repo_name(name,rtype,rstate,private,archived,fork_of,short_name=False,admin=False)">
82 82 <%
83 83 def get_name(name,short_name=short_name):
84 84 if short_name:
85 85 return name.split('/')[-1]
86 86 else:
87 87 return name
88 88 %>
89 89 <div class="${'repo_state_pending' if rstate == 'repo_state_pending' else ''} truncate">
90 90 ##NAME
91 91 <a href="${h.route_path('edit_repo',repo_name=name) if admin else h.route_path('repo_summary',repo_name=name)}">
92 92
93 93 ##TYPE OF REPO
94 94 %if h.is_hg(rtype):
95 95 <span title="${_('Mercurial repository')}"><i class="icon-hg" style="font-size: 14px;"></i></span>
96 96 %elif h.is_git(rtype):
97 97 <span title="${_('Git repository')}"><i class="icon-git" style="font-size: 14px"></i></span>
98 98 %elif h.is_svn(rtype):
99 99 <span title="${_('Subversion repository')}"><i class="icon-svn" style="font-size: 14px"></i></span>
100 100 %endif
101 101
102 102 ##PRIVATE/PUBLIC
103 103 %if private is True and c.visual.show_private_icon:
104 104 <i class="icon-lock" title="${_('Private repository')}"></i>
105 105 %elif private is False and c.visual.show_public_icon:
106 106 <i class="icon-unlock-alt" title="${_('Public repository')}"></i>
107 107 %else:
108 108 <span></span>
109 109 %endif
110 110 ${get_name(name)}
111 111 </a>
112 112 %if fork_of:
113 113 <a href="${h.route_path('repo_summary',repo_name=fork_of.repo_name)}"><i class="icon-code-fork"></i></a>
114 114 %endif
115 115 %if rstate == 'repo_state_pending':
116 116 <span class="creation_in_progress tooltip" title="${_('This repository is being created in a background task')}">
117 117 (${_('creating...')})
118 118 </span>
119 119 %endif
120 120
121 121 </div>
122 122 </%def>
123 123
124 124 <%def name="repo_desc(description, stylify_metatags)">
125 125 <%
126 126 tags, description = h.extract_metatags(description)
127 127 %>
128 128
129 129 <div class="truncate-wrap">
130 130 % if stylify_metatags:
131 131 % for tag_type, tag in tags:
132 132 ${h.style_metatag(tag_type, tag)|n}
133 133 % endfor
134 134 % endif
135 135 ${description}
136 136 </div>
137 137
138 138 </%def>
139 139
140 140 <%def name="last_change(last_change)">
141 141 ${h.age_component(last_change, time_is_local=True)}
142 142 </%def>
143 143
144 144 <%def name="revision(repo_name, rev, commit_id, author, last_msg, commit_date)">
145 145 <div>
146 146 %if rev >= 0:
147 147 <code><a class="tooltip-hovercard" data-hovercard-alt=${h.tooltip(last_msg)} data-hovercard-url="${h.route_path('hovercard_repo_commit', repo_name=repo_name, commit_id=commit_id)}" href="${h.route_path('repo_commit',repo_name=repo_name,commit_id=commit_id)}">${'r{}:{}'.format(rev,h.short_id(commit_id))}</a></code>
148 148 %else:
149 149 ${_('No commits yet')}
150 150 %endif
151 151 </div>
152 152 </%def>
153 153
154 154 <%def name="rss(name)">
155 155 %if c.rhodecode_user.username != h.DEFAULT_USER:
156 156 <a title="${h.tooltip(_('Subscribe to %s rss feed')% name)}" href="${h.route_path('rss_feed_home', repo_name=name, _query=dict(auth_token=c.rhodecode_user.feed_token))}"><i class="icon-rss-sign"></i></a>
157 157 %else:
158 158 <a title="${h.tooltip(_('Subscribe to %s rss feed')% name)}" href="${h.route_path('rss_feed_home', repo_name=name)}"><i class="icon-rss-sign"></i></a>
159 159 %endif
160 160 </%def>
161 161
162 162 <%def name="atom(name)">
163 163 %if c.rhodecode_user.username != h.DEFAULT_USER:
164 164 <a title="${h.tooltip(_('Subscribe to %s atom feed')% name)}" href="${h.route_path('atom_feed_home', repo_name=name, _query=dict(auth_token=c.rhodecode_user.feed_token))}"><i class="icon-rss-sign"></i></a>
165 165 %else:
166 166 <a title="${h.tooltip(_('Subscribe to %s atom feed')% name)}" href="${h.route_path('atom_feed_home', repo_name=name)}"><i class="icon-rss-sign"></i></a>
167 167 %endif
168 168 </%def>
169 169
170 170 <%def name="repo_actions(repo_name, super_user=True)">
171 171 <div>
172 172 <div class="grid_edit">
173 173 <a href="${h.route_path('edit_repo',repo_name=repo_name)}" title="${_('Edit')}">
174 174 Edit
175 175 </a>
176 176 </div>
177 177 <div class="grid_delete">
178 178 ${h.secure_form(h.route_path('edit_repo_advanced_delete', repo_name=repo_name), request=request)}
179 179 ${h.submit('remove_%s' % repo_name,_('Delete'),class_="btn btn-link btn-danger",
180 180 onclick="return confirm('"+_('Confirm to delete this repository: %s') % repo_name+"');")}
181 181 ${h.end_form()}
182 182 </div>
183 183 </div>
184 184 </%def>
185 185
186 186 <%def name="repo_state(repo_state)">
187 187 <div>
188 188 %if repo_state == 'repo_state_pending':
189 189 <div class="tag tag4">${_('Creating')}</div>
190 190 %elif repo_state == 'repo_state_created':
191 191 <div class="tag tag1">${_('Created')}</div>
192 192 %else:
193 193 <div class="tag alert2" title="${h.tooltip(repo_state)}">invalid</div>
194 194 %endif
195 195 </div>
196 196 </%def>
197 197
198 198
199 199 ## REPO GROUP RENDERERS
200 200 <%def name="quick_repo_group_menu(repo_group_name)">
201 201 <i class="icon-more"></i>
202 202 <div class="menu_items_container hidden">
203 203 <ul class="menu_items">
204 204 <li>
205 205 <a href="${h.route_path('repo_group_home', repo_group_name=repo_group_name)}">${_('Summary')}</a>
206 206 </li>
207 207
208 208 </ul>
209 209 </div>
210 210 </%def>
211 211
212 212 <%def name="repo_group_name(repo_group_name, children_groups=None)">
213 213 <div>
214 214 <a href="${h.route_path('repo_group_home', repo_group_name=repo_group_name)}">
215 215 <i class="icon-repo-group" title="${_('Repository group')}" style="font-size: 14px"></i>
216 216 %if children_groups:
217 217 ${h.literal(' &raquo; '.join(children_groups))}
218 218 %else:
219 219 ${repo_group_name}
220 220 %endif
221 221 </a>
222 222 </div>
223 223 </%def>
224 224
225 225 <%def name="repo_group_desc(description, personal, stylify_metatags)">
226 226
227 227 <%
228 228 if stylify_metatags:
229 229 tags, description = h.extract_metatags(description)
230 230 %>
231 231
232 232 <div class="truncate-wrap">
233 233 % if personal:
234 234 <div class="metatag" tag="personal">${_('personal')}</div>
235 235 % endif
236 236
237 237 % if stylify_metatags:
238 238 % for tag_type, tag in tags:
239 239 ${h.style_metatag(tag_type, tag)|n}
240 240 % endfor
241 241 % endif
242 242 ${description}
243 243 </div>
244 244
245 245 </%def>
246 246
247 247 <%def name="repo_group_actions(repo_group_id, repo_group_name, gr_count)">
248 248 <div class="grid_edit">
249 249 <a href="${h.route_path('edit_repo_group',repo_group_name=repo_group_name)}" title="${_('Edit')}">Edit</a>
250 250 </div>
251 251 <div class="grid_delete">
252 252 ${h.secure_form(h.route_path('edit_repo_group_advanced_delete', repo_group_name=repo_group_name), request=request)}
253 253 ${h.submit('remove_%s' % repo_group_name,_('Delete'),class_="btn btn-link btn-danger",
254 254 onclick="return confirm('"+_ungettext('Confirm to delete this group: %s with %s repository','Confirm to delete this group: %s with %s repositories',gr_count) % (repo_group_name, gr_count)+"');")}
255 255 ${h.end_form()}
256 256 </div>
257 257 </%def>
258 258
259 259
260 260 <%def name="user_actions(user_id, username)">
261 261 <div class="grid_edit">
262 262 <a href="${h.route_path('user_edit',user_id=user_id)}" title="${_('Edit')}">
263 263 ${_('Edit')}
264 264 </a>
265 265 </div>
266 266 <div class="grid_delete">
267 267 ${h.secure_form(h.route_path('user_delete', user_id=user_id), request=request)}
268 268 ${h.submit('remove_',_('Delete'),id="remove_user_%s" % user_id, class_="btn btn-link btn-danger",
269 269 onclick="return confirm('"+_('Confirm to delete this user: %s') % username+"');")}
270 270 ${h.end_form()}
271 271 </div>
272 272 </%def>
273 273
274 274 <%def name="user_group_actions(user_group_id, user_group_name)">
275 275 <div class="grid_edit">
276 276 <a href="${h.route_path('edit_user_group', user_group_id=user_group_id)}" title="${_('Edit')}">Edit</a>
277 277 </div>
278 278 <div class="grid_delete">
279 279 ${h.secure_form(h.route_path('user_groups_delete', user_group_id=user_group_id), request=request)}
280 280 ${h.submit('remove_',_('Delete'),id="remove_group_%s" % user_group_id, class_="btn btn-link btn-danger",
281 281 onclick="return confirm('"+_('Confirm to delete this user group: %s') % user_group_name+"');")}
282 282 ${h.end_form()}
283 283 </div>
284 284 </%def>
285 285
286 286
287 287 <%def name="user_name(user_id, username)">
288 288 ${h.link_to(h.person(username, 'username_or_name_or_email'), h.route_path('user_edit', user_id=user_id))}
289 289 </%def>
290 290
291 291 <%def name="user_profile(username)">
292 292 ${base.gravatar_with_user(username, 16, tooltip=True)}
293 293 </%def>
294 294
295 295 <%def name="user_group_name(user_group_name)">
296 296 <div>
297 297 <i class="icon-user-group" title="${_('User group')}"></i>
298 298 ${h.link_to_group(user_group_name)}
299 299 </div>
300 300 </%def>
301 301
302 302
303 303 ## GISTS
304 304
305 305 <%def name="gist_gravatar(full_contact)">
306 306 <div class="gist_gravatar">
307 307 ${base.gravatar(full_contact, 30)}
308 308 </div>
309 309 </%def>
310 310
311 311 <%def name="gist_access_id(gist_access_id, full_contact)">
312 312 <div>
313 <b>
314 <a href="${h.route_path('gist_show', gist_id=gist_access_id)}">gist: ${gist_access_id}</a>
315 </b>
313 <code>
314 <a href="${h.route_path('gist_show', gist_id=gist_access_id)}">${gist_access_id}</a>
315 </code>
316 316 </div>
317 317 </%def>
318 318
319 319 <%def name="gist_author(full_contact, created_on, expires)">
320 320 ${base.gravatar_with_user(full_contact, 16, tooltip=True)}
321 321 </%def>
322 322
323 323
324 324 <%def name="gist_created(created_on)">
325 325 <div class="created">
326 326 ${h.age_component(created_on, time_is_local=True)}
327 327 </div>
328 328 </%def>
329 329
330 330 <%def name="gist_expires(expires)">
331 331 <div class="created">
332 332 %if expires == -1:
333 333 ${_('never')}
334 334 %else:
335 335 ${h.age_component(h.time_to_utcdatetime(expires))}
336 336 %endif
337 337 </div>
338 338 </%def>
339 339
340 340 <%def name="gist_type(gist_type)">
341 341 %if gist_type == 'public':
342 342 <span class="tag tag-gist-public disabled">${_('Public Gist')}</span>
343 343 %else:
344 344 <span class="tag tag-gist-private disabled">${_('Private Gist')}</span>
345 345 %endif
346 346 </%def>
347 347
348 348 <%def name="gist_description(gist_description)">
349 349 ${gist_description}
350 350 </%def>
351 351
352 352
353 353 ## PULL REQUESTS GRID RENDERERS
354 354
355 355 <%def name="pullrequest_target_repo(repo_name)">
356 356 <div class="truncate">
357 357 ${h.link_to(repo_name,h.route_path('repo_summary',repo_name=repo_name))}
358 358 </div>
359 359 </%def>
360 360
361 361 <%def name="pullrequest_status(status)">
362 362 <i class="icon-circle review-status-${status}"></i>
363 363 </%def>
364 364
365 365 <%def name="pullrequest_title(title, description)">
366 366 ${title}
367 367 </%def>
368 368
369 369 <%def name="pullrequest_comments(comments_nr)">
370 370 <i class="icon-comment"></i> ${comments_nr}
371 371 </%def>
372 372
373 373 <%def name="pullrequest_name(pull_request_id, state, is_wip, target_repo_name, short=False)">
374 374 <a href="${h.route_path('pullrequest_show',repo_name=target_repo_name,pull_request_id=pull_request_id)}">
375 375
376 376 % if short:
377 377 !${pull_request_id}
378 378 % else:
379 379 ${_('Pull request !{}').format(pull_request_id)}
380 380 % endif
381 381
382 382 % if state not in ['created']:
383 383 <span class="tag tag-merge-state-${state} tooltip" title="Pull request state is changing">${state}</span>
384 384 % endif
385 385
386 386 % if is_wip:
387 387 <span class="tag tooltip" title="${_('Work in progress')}">wip</span>
388 388 % endif
389 389 </a>
390 390 </%def>
391 391
392 392 <%def name="pullrequest_updated_on(updated_on)">
393 393 ${h.age_component(h.time_to_utcdatetime(updated_on))}
394 394 </%def>
395 395
396 396 <%def name="pullrequest_author(full_contact)">
397 397 ${base.gravatar_with_user(full_contact, 16, tooltip=True)}
398 398 </%def>
399 399
400 400
401 401 ## ARTIFACT RENDERERS
402 402 <%def name="repo_artifact_name(repo_name, file_uid, artifact_display_name)">
403 403 <a href="${h.route_path('repo_artifacts_get', repo_name=repo_name, uid=file_uid)}">
404 404 ${artifact_display_name or '_EMPTY_NAME_'}
405 405 </a>
406 406 </%def>
407 407
408 408 <%def name="repo_artifact_uid(repo_name, file_uid)">
409 409 <code>${h.shorter(file_uid, size=24, prefix=True)}</code>
410 410 </%def>
411 411
412 412 <%def name="repo_artifact_sha256(artifact_sha256)">
413 413 <div class="code">${h.shorter(artifact_sha256, 12)}</div>
414 414 </%def>
415 415
416 416 <%def name="repo_artifact_actions(repo_name, file_store_id, file_uid)">
417 417 ## <div class="grid_edit">
418 418 ## <a href="#Edit" title="${_('Edit')}">${_('Edit')}</a>
419 419 ## </div>
420 420 <div class="grid_edit">
421 421 <a href="${h.route_path('repo_artifacts_info', repo_name=repo_name, uid=file_store_id)}" title="${_('Info')}">${_('Info')}</a>
422 422 </div>
423 423 % if h.HasRepoPermissionAny('repository.admin')(c.repo_name):
424 424 <div class="grid_delete">
425 425 ${h.secure_form(h.route_path('repo_artifacts_delete', repo_name=repo_name, uid=file_store_id), request=request)}
426 426 ${h.submit('remove_',_('Delete'),id="remove_artifact_%s" % file_store_id, class_="btn btn-link btn-danger",
427 427 onclick="return confirm('"+_('Confirm to delete this artifact: %s') % file_uid+"');")}
428 428 ${h.end_form()}
429 429 </div>
430 430 % endif
431 431 </%def>
432 432
433 433 <%def name="markup_form(form_id, form_text='', help_text=None)">
434 434
435 435 <div class="markup-form">
436 436 <div class="markup-form-area">
437 437 <div class="markup-form-area-header">
438 438 <ul class="nav-links clearfix">
439 439 <li class="active">
440 440 <a href="#edit-text" tabindex="-1" id="edit-btn_${form_id}">${_('Write')}</a>
441 441 </li>
442 442 <li class="">
443 443 <a href="#preview-text" tabindex="-1" id="preview-btn_${form_id}">${_('Preview')}</a>
444 444 </li>
445 445 </ul>
446 446 </div>
447 447
448 448 <div class="markup-form-area-write" style="display: block;">
449 449 <div id="edit-container_${form_id}">
450 450 <textarea id="${form_id}" name="${form_id}" class="comment-block-ta ac-input">${form_text if form_text else ''}</textarea>
451 451 </div>
452 452 <div id="preview-container_${form_id}" class="clearfix" style="display: none;">
453 453 <div id="preview-box_${form_id}" class="preview-box"></div>
454 454 </div>
455 455 </div>
456 456
457 457 <div class="markup-form-area-footer">
458 458 <div class="toolbar">
459 459 <div class="toolbar-text">
460 460 ${(_('Parsed using %s syntax') % (
461 461 ('<a href="%s">%s</a>' % (h.route_url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())),
462 462 )
463 463 )|n}
464 464 </div>
465 465 </div>
466 466 </div>
467 467 </div>
468 468
469 469 <div class="markup-form-footer">
470 470 % if help_text:
471 471 <span class="help-block">${help_text}</span>
472 472 % endif
473 473 </div>
474 474 </div>
475 475 <script type="text/javascript">
476 476 new MarkupForm('${form_id}');
477 477 </script>
478 478
479 479 </%def>
General Comments 0
You need to be logged in to leave comments. Login now