##// END OF EJS Templates
changelog: added dynamic loaders to extend number of commits inside changelog....
marcink -
r1379:191eae48 default
parent child Browse files
Show More
@@ -0,0 +1,173 b''
1 // # Copyright (C) 2016-2017 RhodeCode GmbH
2 // #
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
6 // #
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
19
20 var CommitsController = function () {
21 var self = this;
22 this.$graphCanvas = $('#graph_canvas');
23 this.$commitCounter = $('#commit-counter');
24
25 this.getCurrentGraphData = function () {
26 // raw form
27 return self.$graphCanvas.data('commits');
28 };
29
30 this.setLabelText = function (graphData) {
31 var shown = $('.commit_hash').length;
32 var total = self.$commitCounter.data('total');
33
34 if (shown == 1) {
35 var text = _gettext('showing {0} out of {1} commit').format(shown, total);
36 } else {
37 var text = _gettext('showing {0} out of {1} commits').format(shown, total);
38 }
39 self.$commitCounter.html(text)
40 };
41
42 this.reloadGraph = function (chunk) {
43 chunk = chunk || 'next';
44
45 // reset state on re-render !
46 self.$graphCanvas.html('');
47
48 var edgeData = $("[data-graph]").data('graph') || this.$graphCanvas.data('graph') || [];
49
50 // Determine max number of edges per row in graph
51 var edgeCount = 1;
52 $.each(edgeData, function (i, item) {
53 $.each(item[2], function (key, value) {
54 if (value[1] > edgeCount) {
55 edgeCount = value[1];
56 }
57 });
58 });
59
60 var x_step = Math.min(10, Math.floor(86 / edgeCount));
61 var graph_options = {
62 width: 100,
63 height: $('#changesets').find('.commits-range').height(),
64 x_step: x_step,
65 y_step: 42,
66 dotRadius: 3.5,
67 lineWidth: 2.5
68 };
69
70 var prevCommitsData = this.$graphCanvas.data('commits') || [];
71 var nextCommitsData = $("[data-graph]").data('commits') || [];
72
73 if (chunk == 'next') {
74 var commitData = $.merge(prevCommitsData, nextCommitsData);
75 } else {
76 var commitData = $.merge(nextCommitsData, prevCommitsData);
77 }
78
79 this.$graphCanvas.data('graph', edgeData);
80 this.$graphCanvas.data('commits', commitData);
81
82 // destroy dynamic loaded graph
83 $("[data-graph]").remove();
84
85 this.$graphCanvas.commits(graph_options);
86
87 this.setLabelText(edgeData);
88 if ($('.load-more-commits').find('.prev-commits').get(0)) {
89 var padding = 75;
90
91 } else {
92 var padding = 43;
93 }
94 $('#graph_nodes').css({'padding-top': padding});
95 };
96
97 this.getChunkUrl = function (page, chunk, branch) {
98 var urlData = {
99 'repo_name': templateContext.repo_name,
100 'page': page,
101 'chunk': chunk
102 };
103
104 if (branch !== undefined && branch !== '') {
105 urlData['branch'] = branch;
106 }
107
108 return pyroutes.url('changelog_elements', urlData);
109 };
110
111 this.loadNext = function (node, page, branch) {
112 var loadUrl = this.getChunkUrl(page, 'next', branch);
113 var postData = {'graph': JSON.stringify(this.getCurrentGraphData())};
114
115 $.post(loadUrl, postData, function (data) {
116 $(node).closest('tbody').append(data);
117 $(node).closest('td').remove();
118 self.reloadGraph('next');
119 })
120 };
121
122 this.loadPrev = function (node, page, branch) {
123 var loadUrl = this.getChunkUrl(page, 'prev', branch);
124 var postData = {'graph': JSON.stringify(this.getCurrentGraphData())};
125
126 $.post(loadUrl, postData, function (data) {
127 $(node).closest('tbody').prepend(data);
128 $(node).closest('td').remove();
129 self.reloadGraph('prev');
130 })
131 };
132
133 this.expandCommit = function (node) {
134
135 var target_expand = $(node);
136 var cid = target_expand.data('commitId');
137
138 if (target_expand.hasClass('open')) {
139 $('#c-' + cid).css({
140 'height': '1.5em',
141 'white-space': 'nowrap',
142 'text-overflow': 'ellipsis',
143 'overflow': 'hidden'
144 });
145 $('#t-' + cid).css({
146 'height': 'auto',
147 'line-height': '.9em',
148 'text-overflow': 'ellipsis',
149 'overflow': 'hidden',
150 'white-space': 'nowrap'
151 });
152 target_expand.removeClass('open');
153 }
154 else {
155 $('#c-' + cid).css({
156 'height': 'auto',
157 'white-space': 'pre-line',
158 'text-overflow': 'initial',
159 'overflow': 'visible'
160 });
161 $('#t-' + cid).css({
162 'height': 'auto',
163 'max-height': 'none',
164 'text-overflow': 'initial',
165 'overflow': 'visible',
166 'white-space': 'normal'
167 });
168 target_expand.addClass('open');
169 }
170 // redraw the graph
171 self.reloadGraph();
172 }
173 };
@@ -1,190 +1,191 b''
1 1 {
2 2 "dirs": {
3 3 "css": {
4 4 "src":"rhodecode/public/css",
5 5 "dest":"rhodecode/public/css"
6 6 },
7 7 "js": {
8 8 "src": "rhodecode/public/js/src",
9 9 "dest": "rhodecode/public/js",
10 10 "bower": "bower_components",
11 11 "node_modules": "node_modules"
12 12 }
13 13 },
14 14 "copy": {
15 15 "main": {
16 16 "expand": true,
17 17 "cwd": "bower_components",
18 18 "src": "webcomponentsjs/webcomponents-lite.js",
19 19 "dest": "<%= dirs.js.dest %>/vendors"
20 20 }
21 21 },
22 22 "concat": {
23 23 "polymercss": {
24 24 "src": [
25 25 "<%= dirs.js.src %>/components/root-styles-prefix.html",
26 26 "<%= dirs.css.src %>/style-polymer.css",
27 27 "<%= dirs.js.src %>/components/root-styles-suffix.html"
28 28 ],
29 29 "dest": "<%= dirs.js.dest %>/src/components/root-styles.gen.html",
30 30 "nonull": true
31 31 },
32 32 "dist": {
33 33 "src": [
34 34 "<%= dirs.js.src %>/jquery-1.11.1.min.js",
35 35 "<%= dirs.js.src %>/logging.js",
36 36 "<%= dirs.js.src %>/bootstrap.js",
37 37 "<%= dirs.js.src %>/mousetrap.js",
38 38 "<%= dirs.js.src %>/moment.js",
39 39 "<%= dirs.js.node_modules %>/appenlight-client/appenlight-client.min.js",
40 40 "<%= dirs.js.node_modules %>/favico.js/favico-0.3.10.min.js",
41 41 "<%= dirs.js.src %>/i18n_utils.js",
42 42 "<%= dirs.js.src %>/deform.js",
43 43 "<%= dirs.js.src %>/plugins/jquery.pjax.js",
44 44 "<%= dirs.js.src %>/plugins/jquery.dataTables.js",
45 45 "<%= dirs.js.src %>/plugins/flavoured_checkbox.js",
46 46 "<%= dirs.js.src %>/plugins/jquery.auto-grow-input.js",
47 47 "<%= dirs.js.src %>/plugins/jquery.autocomplete.js",
48 48 "<%= dirs.js.src %>/plugins/jquery.debounce.js",
49 49 "<%= dirs.js.src %>/plugins/jquery.mark.js",
50 50 "<%= dirs.js.src %>/plugins/jquery.timeago.js",
51 51 "<%= dirs.js.src %>/plugins/jquery.timeago-extension.js",
52 52 "<%= dirs.js.src %>/select2/select2.js",
53 53 "<%= dirs.js.src %>/codemirror/codemirror.js",
54 54 "<%= dirs.js.src %>/codemirror/codemirror_loadmode.js",
55 55 "<%= dirs.js.src %>/codemirror/codemirror_hint.js",
56 56 "<%= dirs.js.src %>/codemirror/codemirror_overlay.js",
57 57 "<%= dirs.js.src %>/codemirror/codemirror_placeholder.js",
58 58 "<%= dirs.js.dest %>/mode/meta.js",
59 59 "<%= dirs.js.dest %>/mode/meta_ext.js",
60 60 "<%= dirs.js.dest %>/rhodecode/i18n/select2/translations.js",
61 61 "<%= dirs.js.src %>/rhodecode/utils/array.js",
62 62 "<%= dirs.js.src %>/rhodecode/utils/string.js",
63 63 "<%= dirs.js.src %>/rhodecode/utils/pyroutes.js",
64 64 "<%= dirs.js.src %>/rhodecode/utils/ajax.js",
65 65 "<%= dirs.js.src %>/rhodecode/utils/autocomplete.js",
66 66 "<%= dirs.js.src %>/rhodecode/utils/colorgenerator.js",
67 67 "<%= dirs.js.src %>/rhodecode/utils/ie.js",
68 68 "<%= dirs.js.src %>/rhodecode/utils/os.js",
69 69 "<%= dirs.js.src %>/rhodecode/utils/topics.js",
70 70 "<%= dirs.js.src %>/rhodecode/init.js",
71 "<%= dirs.js.src %>/rhodecode/changelog.js",
71 72 "<%= dirs.js.src %>/rhodecode/codemirror.js",
72 73 "<%= dirs.js.src %>/rhodecode/comments.js",
73 74 "<%= dirs.js.src %>/rhodecode/constants.js",
74 75 "<%= dirs.js.src %>/rhodecode/files.js",
75 76 "<%= dirs.js.src %>/rhodecode/followers.js",
76 77 "<%= dirs.js.src %>/rhodecode/menus.js",
77 78 "<%= dirs.js.src %>/rhodecode/notifications.js",
78 79 "<%= dirs.js.src %>/rhodecode/permissions.js",
79 80 "<%= dirs.js.src %>/rhodecode/pjax.js",
80 81 "<%= dirs.js.src %>/rhodecode/pullrequests.js",
81 82 "<%= dirs.js.src %>/rhodecode/settings.js",
82 83 "<%= dirs.js.src %>/rhodecode/select2_widgets.js",
83 84 "<%= dirs.js.src %>/rhodecode/tooltips.js",
84 85 "<%= dirs.js.src %>/rhodecode/users.js",
85 86 "<%= dirs.js.src %>/rhodecode/appenlight.js",
86 87 "<%= dirs.js.src %>/rhodecode.js"
87 88 ],
88 89 "dest": "<%= dirs.js.dest %>/scripts.js",
89 90 "nonull": true
90 91 }
91 92 },
92 93 "crisper": {
93 94 "dist": {
94 95 "options": {
95 96 "cleanup": false,
96 97 "onlySplit": true
97 98 },
98 99 "src": "<%= dirs.js.dest %>/rhodecode-components.html",
99 100 "dest": "<%= dirs.js.dest %>/rhodecode-components.js"
100 101 }
101 102 },
102 103 "less": {
103 104 "development": {
104 105 "options": {
105 106 "compress": false,
106 107 "yuicompress": false,
107 108 "optimization": 0
108 109 },
109 110 "files": {
110 111 "<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less",
111 112 "<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less"
112 113 }
113 114 },
114 115 "production": {
115 116 "options": {
116 117 "compress": true,
117 118 "yuicompress": true,
118 119 "optimization": 2
119 120 },
120 121 "files": {
121 122 "<%= dirs.css.dest %>/style.css": "<%= dirs.css.src %>/main.less",
122 123 "<%= dirs.css.dest %>/style-polymer.css": "<%= dirs.css.src %>/polymer.less"
123 124 }
124 125 },
125 126 "components": {
126 127 "files": [
127 128 {
128 129 "cwd": "<%= dirs.js.src %>/components/",
129 130 "dest": "<%= dirs.js.src %>/components/",
130 131 "src": [
131 132 "**/*.less"
132 133 ],
133 134 "expand": true,
134 135 "ext": ".css"
135 136 }
136 137 ]
137 138 }
138 139 },
139 140 "watch": {
140 141 "less": {
141 142 "files": [
142 143 "<%= dirs.css.src %>/**/*.less",
143 144 "<%= dirs.js.src %>/components/**/*.less"
144 145 ],
145 146 "tasks": [
146 147 "less:development",
147 148 "less:components",
148 149 "concat:polymercss",
149 150 "vulcanize",
150 151 "crisper",
151 152 "concat:dist"
152 153 ]
153 154 },
154 155 "js": {
155 156 "files": [
156 157 "!<%= dirs.js.src %>/components/root-styles.gen.html",
157 158 "<%= dirs.js.src %>/**/*.js",
158 159 "<%= dirs.js.src %>/components/**/*.html"
159 160 ],
160 161 "tasks": [
161 162 "less:components",
162 163 "concat:polymercss",
163 164 "vulcanize",
164 165 "crisper",
165 166 "concat:dist"
166 167 ]
167 168 }
168 169 },
169 170 "jshint": {
170 171 "rhodecode": {
171 172 "src": "<%= dirs.js.src %>/rhodecode/**/*.js",
172 173 "options": {
173 174 "jshintrc": ".jshintrc"
174 175 }
175 176 }
176 177 },
177 178 "vulcanize": {
178 179 "default": {
179 180 "options": {
180 181 "abspath": "",
181 182 "inlineScripts": true,
182 183 "inlineCss": true,
183 184 "stripComments": true
184 185 },
185 186 "files": {
186 187 "<%= dirs.js.dest %>/rhodecode-components.html": "<%= dirs.js.src %>/components/shared-components.html"
187 188 }
188 189 }
189 190 }
190 191 }
@@ -1,1167 +1,1167 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Routes configuration
23 23
24 24 The more specific and detailed routes should be defined first so they
25 25 may take precedent over the more generic routes. For more information
26 26 refer to the routes manual at http://routes.groovie.org/docs/
27 27
28 28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
29 29 and _route_name variable which uses some of stored naming here to do redirects.
30 30 """
31 31 import os
32 32 import re
33 33 from routes import Mapper
34 34
35 35 from rhodecode.config import routing_links
36 36
37 37 # prefix for non repository related links needs to be prefixed with `/`
38 38 ADMIN_PREFIX = '/_admin'
39 39 STATIC_FILE_PREFIX = '/_static'
40 40
41 41 # Default requirements for URL parts
42 42 URL_NAME_REQUIREMENTS = {
43 43 # group name can have a slash in them, but they must not end with a slash
44 44 'group_name': r'.*?[^/]',
45 45 'repo_group_name': r'.*?[^/]',
46 46 # repo names can have a slash in them, but they must not end with a slash
47 47 'repo_name': r'.*?[^/]',
48 48 # file path eats up everything at the end
49 49 'f_path': r'.*',
50 50 # reference types
51 51 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
52 52 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
53 53 }
54 54
55 55
56 56 def add_route_requirements(route_path, requirements):
57 57 """
58 58 Adds regex requirements to pyramid routes using a mapping dict
59 59
60 60 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
61 61 '/{action}/{id:\d+}'
62 62
63 63 """
64 64 for key, regex in requirements.items():
65 65 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
66 66 return route_path
67 67
68 68
69 69 class JSRoutesMapper(Mapper):
70 70 """
71 71 Wrapper for routes.Mapper to make pyroutes compatible url definitions
72 72 """
73 73 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
74 74 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
75 75 def __init__(self, *args, **kw):
76 76 super(JSRoutesMapper, self).__init__(*args, **kw)
77 77 self._jsroutes = []
78 78
79 79 def connect(self, *args, **kw):
80 80 """
81 81 Wrapper for connect to take an extra argument jsroute=True
82 82
83 83 :param jsroute: boolean, if True will add the route to the pyroutes list
84 84 """
85 85 if kw.pop('jsroute', False):
86 86 if not self._named_route_regex.match(args[0]):
87 87 raise Exception('only named routes can be added to pyroutes')
88 88 self._jsroutes.append(args[0])
89 89
90 90 super(JSRoutesMapper, self).connect(*args, **kw)
91 91
92 92 def _extract_route_information(self, route):
93 93 """
94 94 Convert a route into tuple(name, path, args), eg:
95 95 ('user_profile', '/profile/%(username)s', ['username'])
96 96 """
97 97 routepath = route.routepath
98 98 def replace(matchobj):
99 99 if matchobj.group(1):
100 100 return "%%(%s)s" % matchobj.group(1).split(':')[0]
101 101 else:
102 102 return "%%(%s)s" % matchobj.group(2)
103 103
104 104 routepath = self._argument_prog.sub(replace, routepath)
105 105 return (
106 106 route.name,
107 107 routepath,
108 108 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
109 109 for arg in self._argument_prog.findall(route.routepath)]
110 110 )
111 111
112 112 def jsroutes(self):
113 113 """
114 114 Return a list of pyroutes.js compatible routes
115 115 """
116 116 for route_name in self._jsroutes:
117 117 yield self._extract_route_information(self._routenames[route_name])
118 118
119 119
120 120 def make_map(config):
121 121 """Create, configure and return the routes Mapper"""
122 122 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
123 123 always_scan=config['debug'])
124 124 rmap.minimization = False
125 125 rmap.explicit = False
126 126
127 127 from rhodecode.lib.utils2 import str2bool
128 128 from rhodecode.model import repo, repo_group
129 129
130 130 def check_repo(environ, match_dict):
131 131 """
132 132 check for valid repository for proper 404 handling
133 133
134 134 :param environ:
135 135 :param match_dict:
136 136 """
137 137 repo_name = match_dict.get('repo_name')
138 138
139 139 if match_dict.get('f_path'):
140 140 # fix for multiple initial slashes that causes errors
141 141 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
142 142 repo_model = repo.RepoModel()
143 143 by_name_match = repo_model.get_by_repo_name(repo_name)
144 144 # if we match quickly from database, short circuit the operation,
145 145 # and validate repo based on the type.
146 146 if by_name_match:
147 147 return True
148 148
149 149 by_id_match = repo_model.get_repo_by_id(repo_name)
150 150 if by_id_match:
151 151 repo_name = by_id_match.repo_name
152 152 match_dict['repo_name'] = repo_name
153 153 return True
154 154
155 155 return False
156 156
157 157 def check_group(environ, match_dict):
158 158 """
159 159 check for valid repository group path for proper 404 handling
160 160
161 161 :param environ:
162 162 :param match_dict:
163 163 """
164 164 repo_group_name = match_dict.get('group_name')
165 165 repo_group_model = repo_group.RepoGroupModel()
166 166 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
167 167 if by_name_match:
168 168 return True
169 169
170 170 return False
171 171
172 172 def check_user_group(environ, match_dict):
173 173 """
174 174 check for valid user group for proper 404 handling
175 175
176 176 :param environ:
177 177 :param match_dict:
178 178 """
179 179 return True
180 180
181 181 def check_int(environ, match_dict):
182 182 return match_dict.get('id').isdigit()
183 183
184 184
185 185 #==========================================================================
186 186 # CUSTOM ROUTES HERE
187 187 #==========================================================================
188 188
189 189 # MAIN PAGE
190 190 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
191 191 rmap.connect('goto_switcher_data', '/_goto_data', controller='home',
192 192 action='goto_switcher_data')
193 193 rmap.connect('repo_list_data', '/_repos', controller='home',
194 194 action='repo_list_data')
195 195
196 196 rmap.connect('user_autocomplete_data', '/_users', controller='home',
197 197 action='user_autocomplete_data', jsroute=True)
198 198 rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home',
199 199 action='user_group_autocomplete_data', jsroute=True)
200 200
201 201 rmap.connect(
202 202 'user_profile', '/_profiles/{username}', controller='users',
203 203 action='user_profile')
204 204
205 205 # TODO: johbo: Static links, to be replaced by our redirection mechanism
206 206 rmap.connect('rst_help',
207 207 'http://docutils.sourceforge.net/docs/user/rst/quickref.html',
208 208 _static=True)
209 209 rmap.connect('markdown_help',
210 210 'http://daringfireball.net/projects/markdown/syntax',
211 211 _static=True)
212 212 rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True)
213 213 rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True)
214 214 rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True)
215 215 # TODO: anderson - making this a static link since redirect won't play
216 216 # nice with POST requests
217 217 rmap.connect('enterprise_license_convert_from_old',
218 218 'https://rhodecode.com/u/license-upgrade',
219 219 _static=True)
220 220
221 221 routing_links.connect_redirection_links(rmap)
222 222
223 223 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
224 224 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
225 225
226 226 # ADMIN REPOSITORY ROUTES
227 227 with rmap.submapper(path_prefix=ADMIN_PREFIX,
228 228 controller='admin/repos') as m:
229 229 m.connect('repos', '/repos',
230 230 action='create', conditions={'method': ['POST']})
231 231 m.connect('repos', '/repos',
232 232 action='index', conditions={'method': ['GET']})
233 233 m.connect('new_repo', '/create_repository', jsroute=True,
234 234 action='create_repository', conditions={'method': ['GET']})
235 235 m.connect('/repos/{repo_name}',
236 236 action='update', conditions={'method': ['PUT'],
237 237 'function': check_repo},
238 238 requirements=URL_NAME_REQUIREMENTS)
239 239 m.connect('delete_repo', '/repos/{repo_name}',
240 240 action='delete', conditions={'method': ['DELETE']},
241 241 requirements=URL_NAME_REQUIREMENTS)
242 242 m.connect('repo', '/repos/{repo_name}',
243 243 action='show', conditions={'method': ['GET'],
244 244 'function': check_repo},
245 245 requirements=URL_NAME_REQUIREMENTS)
246 246
247 247 # ADMIN REPOSITORY GROUPS ROUTES
248 248 with rmap.submapper(path_prefix=ADMIN_PREFIX,
249 249 controller='admin/repo_groups') as m:
250 250 m.connect('repo_groups', '/repo_groups',
251 251 action='create', conditions={'method': ['POST']})
252 252 m.connect('repo_groups', '/repo_groups',
253 253 action='index', conditions={'method': ['GET']})
254 254 m.connect('new_repo_group', '/repo_groups/new',
255 255 action='new', conditions={'method': ['GET']})
256 256 m.connect('update_repo_group', '/repo_groups/{group_name}',
257 257 action='update', conditions={'method': ['PUT'],
258 258 'function': check_group},
259 259 requirements=URL_NAME_REQUIREMENTS)
260 260
261 261 # EXTRAS REPO GROUP ROUTES
262 262 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
263 263 action='edit',
264 264 conditions={'method': ['GET'], 'function': check_group},
265 265 requirements=URL_NAME_REQUIREMENTS)
266 266 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
267 267 action='edit',
268 268 conditions={'method': ['PUT'], 'function': check_group},
269 269 requirements=URL_NAME_REQUIREMENTS)
270 270
271 271 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
272 272 action='edit_repo_group_advanced',
273 273 conditions={'method': ['GET'], 'function': check_group},
274 274 requirements=URL_NAME_REQUIREMENTS)
275 275 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
276 276 action='edit_repo_group_advanced',
277 277 conditions={'method': ['PUT'], 'function': check_group},
278 278 requirements=URL_NAME_REQUIREMENTS)
279 279
280 280 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
281 281 action='edit_repo_group_perms',
282 282 conditions={'method': ['GET'], 'function': check_group},
283 283 requirements=URL_NAME_REQUIREMENTS)
284 284 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
285 285 action='update_perms',
286 286 conditions={'method': ['PUT'], 'function': check_group},
287 287 requirements=URL_NAME_REQUIREMENTS)
288 288
289 289 m.connect('delete_repo_group', '/repo_groups/{group_name}',
290 290 action='delete', conditions={'method': ['DELETE'],
291 291 'function': check_group},
292 292 requirements=URL_NAME_REQUIREMENTS)
293 293
294 294 # ADMIN USER ROUTES
295 295 with rmap.submapper(path_prefix=ADMIN_PREFIX,
296 296 controller='admin/users') as m:
297 297 m.connect('users', '/users',
298 298 action='create', conditions={'method': ['POST']})
299 299 m.connect('users', '/users',
300 300 action='index', conditions={'method': ['GET']})
301 301 m.connect('new_user', '/users/new',
302 302 action='new', conditions={'method': ['GET']})
303 303 m.connect('update_user', '/users/{user_id}',
304 304 action='update', conditions={'method': ['PUT']})
305 305 m.connect('delete_user', '/users/{user_id}',
306 306 action='delete', conditions={'method': ['DELETE']})
307 307 m.connect('edit_user', '/users/{user_id}/edit',
308 308 action='edit', conditions={'method': ['GET']}, jsroute=True)
309 309 m.connect('user', '/users/{user_id}',
310 310 action='show', conditions={'method': ['GET']})
311 311 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
312 312 action='reset_password', conditions={'method': ['POST']})
313 313 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
314 314 action='create_personal_repo_group', conditions={'method': ['POST']})
315 315
316 316 # EXTRAS USER ROUTES
317 317 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
318 318 action='edit_advanced', conditions={'method': ['GET']})
319 319 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
320 320 action='update_advanced', conditions={'method': ['PUT']})
321 321
322 322 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
323 323 action='edit_auth_tokens', conditions={'method': ['GET']})
324 324 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
325 325 action='add_auth_token', conditions={'method': ['PUT']})
326 326 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
327 327 action='delete_auth_token', conditions={'method': ['DELETE']})
328 328
329 329 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
330 330 action='edit_global_perms', conditions={'method': ['GET']})
331 331 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
332 332 action='update_global_perms', conditions={'method': ['PUT']})
333 333
334 334 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
335 335 action='edit_perms_summary', conditions={'method': ['GET']})
336 336
337 337 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
338 338 action='edit_emails', conditions={'method': ['GET']})
339 339 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
340 340 action='add_email', conditions={'method': ['PUT']})
341 341 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
342 342 action='delete_email', conditions={'method': ['DELETE']})
343 343
344 344 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
345 345 action='edit_ips', conditions={'method': ['GET']})
346 346 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
347 347 action='add_ip', conditions={'method': ['PUT']})
348 348 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
349 349 action='delete_ip', conditions={'method': ['DELETE']})
350 350
351 351 # ADMIN USER GROUPS REST ROUTES
352 352 with rmap.submapper(path_prefix=ADMIN_PREFIX,
353 353 controller='admin/user_groups') as m:
354 354 m.connect('users_groups', '/user_groups',
355 355 action='create', conditions={'method': ['POST']})
356 356 m.connect('users_groups', '/user_groups',
357 357 action='index', conditions={'method': ['GET']})
358 358 m.connect('new_users_group', '/user_groups/new',
359 359 action='new', conditions={'method': ['GET']})
360 360 m.connect('update_users_group', '/user_groups/{user_group_id}',
361 361 action='update', conditions={'method': ['PUT']})
362 362 m.connect('delete_users_group', '/user_groups/{user_group_id}',
363 363 action='delete', conditions={'method': ['DELETE']})
364 364 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
365 365 action='edit', conditions={'method': ['GET']},
366 366 function=check_user_group)
367 367
368 368 # EXTRAS USER GROUP ROUTES
369 369 m.connect('edit_user_group_global_perms',
370 370 '/user_groups/{user_group_id}/edit/global_permissions',
371 371 action='edit_global_perms', conditions={'method': ['GET']})
372 372 m.connect('edit_user_group_global_perms',
373 373 '/user_groups/{user_group_id}/edit/global_permissions',
374 374 action='update_global_perms', conditions={'method': ['PUT']})
375 375 m.connect('edit_user_group_perms_summary',
376 376 '/user_groups/{user_group_id}/edit/permissions_summary',
377 377 action='edit_perms_summary', conditions={'method': ['GET']})
378 378
379 379 m.connect('edit_user_group_perms',
380 380 '/user_groups/{user_group_id}/edit/permissions',
381 381 action='edit_perms', conditions={'method': ['GET']})
382 382 m.connect('edit_user_group_perms',
383 383 '/user_groups/{user_group_id}/edit/permissions',
384 384 action='update_perms', conditions={'method': ['PUT']})
385 385
386 386 m.connect('edit_user_group_advanced',
387 387 '/user_groups/{user_group_id}/edit/advanced',
388 388 action='edit_advanced', conditions={'method': ['GET']})
389 389
390 390 m.connect('edit_user_group_members',
391 391 '/user_groups/{user_group_id}/edit/members', jsroute=True,
392 392 action='user_group_members', conditions={'method': ['GET']})
393 393
394 394 # ADMIN PERMISSIONS ROUTES
395 395 with rmap.submapper(path_prefix=ADMIN_PREFIX,
396 396 controller='admin/permissions') as m:
397 397 m.connect('admin_permissions_application', '/permissions/application',
398 398 action='permission_application_update', conditions={'method': ['POST']})
399 399 m.connect('admin_permissions_application', '/permissions/application',
400 400 action='permission_application', conditions={'method': ['GET']})
401 401
402 402 m.connect('admin_permissions_global', '/permissions/global',
403 403 action='permission_global_update', conditions={'method': ['POST']})
404 404 m.connect('admin_permissions_global', '/permissions/global',
405 405 action='permission_global', conditions={'method': ['GET']})
406 406
407 407 m.connect('admin_permissions_object', '/permissions/object',
408 408 action='permission_objects_update', conditions={'method': ['POST']})
409 409 m.connect('admin_permissions_object', '/permissions/object',
410 410 action='permission_objects', conditions={'method': ['GET']})
411 411
412 412 m.connect('admin_permissions_ips', '/permissions/ips',
413 413 action='permission_ips', conditions={'method': ['POST']})
414 414 m.connect('admin_permissions_ips', '/permissions/ips',
415 415 action='permission_ips', conditions={'method': ['GET']})
416 416
417 417 m.connect('admin_permissions_overview', '/permissions/overview',
418 418 action='permission_perms', conditions={'method': ['GET']})
419 419
420 420 # ADMIN DEFAULTS REST ROUTES
421 421 with rmap.submapper(path_prefix=ADMIN_PREFIX,
422 422 controller='admin/defaults') as m:
423 423 m.connect('admin_defaults_repositories', '/defaults/repositories',
424 424 action='update_repository_defaults', conditions={'method': ['POST']})
425 425 m.connect('admin_defaults_repositories', '/defaults/repositories',
426 426 action='index', conditions={'method': ['GET']})
427 427
428 428 # ADMIN DEBUG STYLE ROUTES
429 429 if str2bool(config.get('debug_style')):
430 430 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
431 431 controller='debug_style') as m:
432 432 m.connect('debug_style_home', '',
433 433 action='index', conditions={'method': ['GET']})
434 434 m.connect('debug_style_template', '/t/{t_path}',
435 435 action='template', conditions={'method': ['GET']})
436 436
437 437 # ADMIN SETTINGS ROUTES
438 438 with rmap.submapper(path_prefix=ADMIN_PREFIX,
439 439 controller='admin/settings') as m:
440 440
441 441 # default
442 442 m.connect('admin_settings', '/settings',
443 443 action='settings_global_update',
444 444 conditions={'method': ['POST']})
445 445 m.connect('admin_settings', '/settings',
446 446 action='settings_global', conditions={'method': ['GET']})
447 447
448 448 m.connect('admin_settings_vcs', '/settings/vcs',
449 449 action='settings_vcs_update',
450 450 conditions={'method': ['POST']})
451 451 m.connect('admin_settings_vcs', '/settings/vcs',
452 452 action='settings_vcs',
453 453 conditions={'method': ['GET']})
454 454 m.connect('admin_settings_vcs', '/settings/vcs',
455 455 action='delete_svn_pattern',
456 456 conditions={'method': ['DELETE']})
457 457
458 458 m.connect('admin_settings_mapping', '/settings/mapping',
459 459 action='settings_mapping_update',
460 460 conditions={'method': ['POST']})
461 461 m.connect('admin_settings_mapping', '/settings/mapping',
462 462 action='settings_mapping', conditions={'method': ['GET']})
463 463
464 464 m.connect('admin_settings_global', '/settings/global',
465 465 action='settings_global_update',
466 466 conditions={'method': ['POST']})
467 467 m.connect('admin_settings_global', '/settings/global',
468 468 action='settings_global', conditions={'method': ['GET']})
469 469
470 470 m.connect('admin_settings_visual', '/settings/visual',
471 471 action='settings_visual_update',
472 472 conditions={'method': ['POST']})
473 473 m.connect('admin_settings_visual', '/settings/visual',
474 474 action='settings_visual', conditions={'method': ['GET']})
475 475
476 476 m.connect('admin_settings_issuetracker',
477 477 '/settings/issue-tracker', action='settings_issuetracker',
478 478 conditions={'method': ['GET']})
479 479 m.connect('admin_settings_issuetracker_save',
480 480 '/settings/issue-tracker/save',
481 481 action='settings_issuetracker_save',
482 482 conditions={'method': ['POST']})
483 483 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
484 484 action='settings_issuetracker_test',
485 485 conditions={'method': ['POST']})
486 486 m.connect('admin_issuetracker_delete',
487 487 '/settings/issue-tracker/delete',
488 488 action='settings_issuetracker_delete',
489 489 conditions={'method': ['DELETE']})
490 490
491 491 m.connect('admin_settings_email', '/settings/email',
492 492 action='settings_email_update',
493 493 conditions={'method': ['POST']})
494 494 m.connect('admin_settings_email', '/settings/email',
495 495 action='settings_email', conditions={'method': ['GET']})
496 496
497 497 m.connect('admin_settings_hooks', '/settings/hooks',
498 498 action='settings_hooks_update',
499 499 conditions={'method': ['POST', 'DELETE']})
500 500 m.connect('admin_settings_hooks', '/settings/hooks',
501 501 action='settings_hooks', conditions={'method': ['GET']})
502 502
503 503 m.connect('admin_settings_search', '/settings/search',
504 504 action='settings_search', conditions={'method': ['GET']})
505 505
506 506 m.connect('admin_settings_supervisor', '/settings/supervisor',
507 507 action='settings_supervisor', conditions={'method': ['GET']})
508 508 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
509 509 action='settings_supervisor_log', conditions={'method': ['GET']})
510 510
511 511 m.connect('admin_settings_labs', '/settings/labs',
512 512 action='settings_labs_update',
513 513 conditions={'method': ['POST']})
514 514 m.connect('admin_settings_labs', '/settings/labs',
515 515 action='settings_labs', conditions={'method': ['GET']})
516 516
517 517 # ADMIN MY ACCOUNT
518 518 with rmap.submapper(path_prefix=ADMIN_PREFIX,
519 519 controller='admin/my_account') as m:
520 520
521 521 m.connect('my_account', '/my_account',
522 522 action='my_account', conditions={'method': ['GET']})
523 523 m.connect('my_account_edit', '/my_account/edit',
524 524 action='my_account_edit', conditions={'method': ['GET']})
525 525 m.connect('my_account', '/my_account',
526 526 action='my_account_update', conditions={'method': ['POST']})
527 527
528 528 m.connect('my_account_password', '/my_account/password',
529 529 action='my_account_password', conditions={'method': ['GET', 'POST']})
530 530
531 531 m.connect('my_account_repos', '/my_account/repos',
532 532 action='my_account_repos', conditions={'method': ['GET']})
533 533
534 534 m.connect('my_account_watched', '/my_account/watched',
535 535 action='my_account_watched', conditions={'method': ['GET']})
536 536
537 537 m.connect('my_account_pullrequests', '/my_account/pull_requests',
538 538 action='my_account_pullrequests', conditions={'method': ['GET']})
539 539
540 540 m.connect('my_account_perms', '/my_account/perms',
541 541 action='my_account_perms', conditions={'method': ['GET']})
542 542
543 543 m.connect('my_account_emails', '/my_account/emails',
544 544 action='my_account_emails', conditions={'method': ['GET']})
545 545 m.connect('my_account_emails', '/my_account/emails',
546 546 action='my_account_emails_add', conditions={'method': ['POST']})
547 547 m.connect('my_account_emails', '/my_account/emails',
548 548 action='my_account_emails_delete', conditions={'method': ['DELETE']})
549 549
550 550 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
551 551 action='my_account_auth_tokens', conditions={'method': ['GET']})
552 552 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
553 553 action='my_account_auth_tokens_add', conditions={'method': ['POST']})
554 554 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
555 555 action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']})
556 556 m.connect('my_account_notifications', '/my_account/notifications',
557 557 action='my_notifications',
558 558 conditions={'method': ['GET']})
559 559 m.connect('my_account_notifications_toggle_visibility',
560 560 '/my_account/toggle_visibility',
561 561 action='my_notifications_toggle_visibility',
562 562 conditions={'method': ['POST']})
563 563 m.connect('my_account_notifications_test_channelstream',
564 564 '/my_account/test_channelstream',
565 565 action='my_account_notifications_test_channelstream',
566 566 conditions={'method': ['POST']})
567 567
568 568 # NOTIFICATION REST ROUTES
569 569 with rmap.submapper(path_prefix=ADMIN_PREFIX,
570 570 controller='admin/notifications') as m:
571 571 m.connect('notifications', '/notifications',
572 572 action='index', conditions={'method': ['GET']})
573 573 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
574 574 action='mark_all_read', conditions={'method': ['POST']})
575 575 m.connect('/notifications/{notification_id}',
576 576 action='update', conditions={'method': ['PUT']})
577 577 m.connect('/notifications/{notification_id}',
578 578 action='delete', conditions={'method': ['DELETE']})
579 579 m.connect('notification', '/notifications/{notification_id}',
580 580 action='show', conditions={'method': ['GET']})
581 581
582 582 # ADMIN GIST
583 583 with rmap.submapper(path_prefix=ADMIN_PREFIX,
584 584 controller='admin/gists') as m:
585 585 m.connect('gists', '/gists',
586 586 action='create', conditions={'method': ['POST']})
587 587 m.connect('gists', '/gists', jsroute=True,
588 588 action='index', conditions={'method': ['GET']})
589 589 m.connect('new_gist', '/gists/new', jsroute=True,
590 590 action='new', conditions={'method': ['GET']})
591 591
592 592 m.connect('/gists/{gist_id}',
593 593 action='delete', conditions={'method': ['DELETE']})
594 594 m.connect('edit_gist', '/gists/{gist_id}/edit',
595 595 action='edit_form', conditions={'method': ['GET']})
596 596 m.connect('edit_gist', '/gists/{gist_id}/edit',
597 597 action='edit', conditions={'method': ['POST']})
598 598 m.connect(
599 599 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
600 600 action='check_revision', conditions={'method': ['GET']})
601 601
602 602 m.connect('gist', '/gists/{gist_id}',
603 603 action='show', conditions={'method': ['GET']})
604 604 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
605 605 revision='tip',
606 606 action='show', conditions={'method': ['GET']})
607 607 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
608 608 revision='tip',
609 609 action='show', conditions={'method': ['GET']})
610 610 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
611 611 revision='tip',
612 612 action='show', conditions={'method': ['GET']},
613 613 requirements=URL_NAME_REQUIREMENTS)
614 614
615 615 # ADMIN MAIN PAGES
616 616 with rmap.submapper(path_prefix=ADMIN_PREFIX,
617 617 controller='admin/admin') as m:
618 618 m.connect('admin_home', '', action='index')
619 619 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
620 620 action='add_repo')
621 621 m.connect(
622 622 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
623 623 action='pull_requests')
624 624 m.connect(
625 625 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
626 626 action='pull_requests')
627 627 m.connect(
628 628 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
629 629 action='pull_requests')
630 630
631 631 # USER JOURNAL
632 632 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
633 633 controller='journal', action='index')
634 634 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
635 635 controller='journal', action='journal_rss')
636 636 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
637 637 controller='journal', action='journal_atom')
638 638
639 639 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
640 640 controller='journal', action='public_journal')
641 641
642 642 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
643 643 controller='journal', action='public_journal_rss')
644 644
645 645 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
646 646 controller='journal', action='public_journal_rss')
647 647
648 648 rmap.connect('public_journal_atom',
649 649 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
650 650 action='public_journal_atom')
651 651
652 652 rmap.connect('public_journal_atom_old',
653 653 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
654 654 action='public_journal_atom')
655 655
656 656 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
657 657 controller='journal', action='toggle_following', jsroute=True,
658 658 conditions={'method': ['POST']})
659 659
660 660 # FULL TEXT SEARCH
661 661 rmap.connect('search', '%s/search' % (ADMIN_PREFIX,),
662 662 controller='search')
663 663 rmap.connect('search_repo_home', '/{repo_name}/search',
664 664 controller='search',
665 665 action='index',
666 666 conditions={'function': check_repo},
667 667 requirements=URL_NAME_REQUIREMENTS)
668 668
669 669 # FEEDS
670 670 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
671 671 controller='feed', action='rss',
672 672 conditions={'function': check_repo},
673 673 requirements=URL_NAME_REQUIREMENTS)
674 674
675 675 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
676 676 controller='feed', action='atom',
677 677 conditions={'function': check_repo},
678 678 requirements=URL_NAME_REQUIREMENTS)
679 679
680 680 #==========================================================================
681 681 # REPOSITORY ROUTES
682 682 #==========================================================================
683 683
684 684 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
685 685 controller='admin/repos', action='repo_creating',
686 686 requirements=URL_NAME_REQUIREMENTS)
687 687 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
688 688 controller='admin/repos', action='repo_check',
689 689 requirements=URL_NAME_REQUIREMENTS)
690 690
691 691 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
692 692 controller='summary', action='repo_stats',
693 693 conditions={'function': check_repo},
694 694 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
695 695
696 696 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
697 697 controller='summary', action='repo_refs_data',
698 698 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
699 699 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
700 700 controller='summary', action='repo_refs_changelog_data',
701 701 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
702 702 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
703 703 controller='summary', action='repo_default_reviewers_data',
704 704 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
705 705
706 706 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
707 707 controller='changeset', revision='tip',
708 708 conditions={'function': check_repo},
709 709 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
710 710 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
711 711 controller='changeset', revision='tip', action='changeset_children',
712 712 conditions={'function': check_repo},
713 713 requirements=URL_NAME_REQUIREMENTS)
714 714 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
715 715 controller='changeset', revision='tip', action='changeset_parents',
716 716 conditions={'function': check_repo},
717 717 requirements=URL_NAME_REQUIREMENTS)
718 718
719 719 # repo edit options
720 720 rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True,
721 721 controller='admin/repos', action='edit',
722 722 conditions={'method': ['GET'], 'function': check_repo},
723 723 requirements=URL_NAME_REQUIREMENTS)
724 724
725 725 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
726 726 jsroute=True,
727 727 controller='admin/repos', action='edit_permissions',
728 728 conditions={'method': ['GET'], 'function': check_repo},
729 729 requirements=URL_NAME_REQUIREMENTS)
730 730 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
731 731 controller='admin/repos', action='edit_permissions_update',
732 732 conditions={'method': ['PUT'], 'function': check_repo},
733 733 requirements=URL_NAME_REQUIREMENTS)
734 734
735 735 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
736 736 controller='admin/repos', action='edit_fields',
737 737 conditions={'method': ['GET'], 'function': check_repo},
738 738 requirements=URL_NAME_REQUIREMENTS)
739 739 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
740 740 controller='admin/repos', action='create_repo_field',
741 741 conditions={'method': ['PUT'], 'function': check_repo},
742 742 requirements=URL_NAME_REQUIREMENTS)
743 743 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
744 744 controller='admin/repos', action='delete_repo_field',
745 745 conditions={'method': ['DELETE'], 'function': check_repo},
746 746 requirements=URL_NAME_REQUIREMENTS)
747 747
748 748 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
749 749 controller='admin/repos', action='edit_advanced',
750 750 conditions={'method': ['GET'], 'function': check_repo},
751 751 requirements=URL_NAME_REQUIREMENTS)
752 752
753 753 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
754 754 controller='admin/repos', action='edit_advanced_locking',
755 755 conditions={'method': ['PUT'], 'function': check_repo},
756 756 requirements=URL_NAME_REQUIREMENTS)
757 757 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
758 758 controller='admin/repos', action='toggle_locking',
759 759 conditions={'method': ['GET'], 'function': check_repo},
760 760 requirements=URL_NAME_REQUIREMENTS)
761 761
762 762 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
763 763 controller='admin/repos', action='edit_advanced_journal',
764 764 conditions={'method': ['PUT'], 'function': check_repo},
765 765 requirements=URL_NAME_REQUIREMENTS)
766 766
767 767 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
768 768 controller='admin/repos', action='edit_advanced_fork',
769 769 conditions={'method': ['PUT'], 'function': check_repo},
770 770 requirements=URL_NAME_REQUIREMENTS)
771 771
772 772 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
773 773 controller='admin/repos', action='edit_caches_form',
774 774 conditions={'method': ['GET'], 'function': check_repo},
775 775 requirements=URL_NAME_REQUIREMENTS)
776 776 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
777 777 controller='admin/repos', action='edit_caches',
778 778 conditions={'method': ['PUT'], 'function': check_repo},
779 779 requirements=URL_NAME_REQUIREMENTS)
780 780
781 781 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
782 782 controller='admin/repos', action='edit_remote_form',
783 783 conditions={'method': ['GET'], 'function': check_repo},
784 784 requirements=URL_NAME_REQUIREMENTS)
785 785 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
786 786 controller='admin/repos', action='edit_remote',
787 787 conditions={'method': ['PUT'], 'function': check_repo},
788 788 requirements=URL_NAME_REQUIREMENTS)
789 789
790 790 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
791 791 controller='admin/repos', action='edit_statistics_form',
792 792 conditions={'method': ['GET'], 'function': check_repo},
793 793 requirements=URL_NAME_REQUIREMENTS)
794 794 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
795 795 controller='admin/repos', action='edit_statistics',
796 796 conditions={'method': ['PUT'], 'function': check_repo},
797 797 requirements=URL_NAME_REQUIREMENTS)
798 798 rmap.connect('repo_settings_issuetracker',
799 799 '/{repo_name}/settings/issue-tracker',
800 800 controller='admin/repos', action='repo_issuetracker',
801 801 conditions={'method': ['GET'], 'function': check_repo},
802 802 requirements=URL_NAME_REQUIREMENTS)
803 803 rmap.connect('repo_issuetracker_test',
804 804 '/{repo_name}/settings/issue-tracker/test',
805 805 controller='admin/repos', action='repo_issuetracker_test',
806 806 conditions={'method': ['POST'], 'function': check_repo},
807 807 requirements=URL_NAME_REQUIREMENTS)
808 808 rmap.connect('repo_issuetracker_delete',
809 809 '/{repo_name}/settings/issue-tracker/delete',
810 810 controller='admin/repos', action='repo_issuetracker_delete',
811 811 conditions={'method': ['DELETE'], 'function': check_repo},
812 812 requirements=URL_NAME_REQUIREMENTS)
813 813 rmap.connect('repo_issuetracker_save',
814 814 '/{repo_name}/settings/issue-tracker/save',
815 815 controller='admin/repos', action='repo_issuetracker_save',
816 816 conditions={'method': ['POST'], 'function': check_repo},
817 817 requirements=URL_NAME_REQUIREMENTS)
818 818 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
819 819 controller='admin/repos', action='repo_settings_vcs_update',
820 820 conditions={'method': ['POST'], 'function': check_repo},
821 821 requirements=URL_NAME_REQUIREMENTS)
822 822 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
823 823 controller='admin/repos', action='repo_settings_vcs',
824 824 conditions={'method': ['GET'], 'function': check_repo},
825 825 requirements=URL_NAME_REQUIREMENTS)
826 826 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
827 827 controller='admin/repos', action='repo_delete_svn_pattern',
828 828 conditions={'method': ['DELETE'], 'function': check_repo},
829 829 requirements=URL_NAME_REQUIREMENTS)
830 830 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
831 831 controller='admin/repos', action='repo_settings_pullrequest',
832 832 conditions={'method': ['GET', 'POST'], 'function': check_repo},
833 833 requirements=URL_NAME_REQUIREMENTS)
834 834
835 835 # still working url for backward compat.
836 836 rmap.connect('raw_changeset_home_depraced',
837 837 '/{repo_name}/raw-changeset/{revision}',
838 838 controller='changeset', action='changeset_raw',
839 839 revision='tip', conditions={'function': check_repo},
840 840 requirements=URL_NAME_REQUIREMENTS)
841 841
842 842 # new URLs
843 843 rmap.connect('changeset_raw_home',
844 844 '/{repo_name}/changeset-diff/{revision}',
845 845 controller='changeset', action='changeset_raw',
846 846 revision='tip', conditions={'function': check_repo},
847 847 requirements=URL_NAME_REQUIREMENTS)
848 848
849 849 rmap.connect('changeset_patch_home',
850 850 '/{repo_name}/changeset-patch/{revision}',
851 851 controller='changeset', action='changeset_patch',
852 852 revision='tip', conditions={'function': check_repo},
853 853 requirements=URL_NAME_REQUIREMENTS)
854 854
855 855 rmap.connect('changeset_download_home',
856 856 '/{repo_name}/changeset-download/{revision}',
857 857 controller='changeset', action='changeset_download',
858 858 revision='tip', conditions={'function': check_repo},
859 859 requirements=URL_NAME_REQUIREMENTS)
860 860
861 861 rmap.connect('changeset_comment',
862 862 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
863 863 controller='changeset', revision='tip', action='comment',
864 864 conditions={'function': check_repo},
865 865 requirements=URL_NAME_REQUIREMENTS)
866 866
867 867 rmap.connect('changeset_comment_preview',
868 868 '/{repo_name}/changeset/comment/preview', jsroute=True,
869 869 controller='changeset', action='preview_comment',
870 870 conditions={'function': check_repo, 'method': ['POST']},
871 871 requirements=URL_NAME_REQUIREMENTS)
872 872
873 873 rmap.connect('changeset_comment_delete',
874 874 '/{repo_name}/changeset/comment/{comment_id}/delete',
875 875 controller='changeset', action='delete_comment',
876 876 conditions={'function': check_repo, 'method': ['DELETE']},
877 877 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
878 878
879 879 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
880 880 controller='changeset', action='changeset_info',
881 881 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
882 882
883 883 rmap.connect('compare_home',
884 884 '/{repo_name}/compare',
885 885 controller='compare', action='index',
886 886 conditions={'function': check_repo},
887 887 requirements=URL_NAME_REQUIREMENTS)
888 888
889 889 rmap.connect('compare_url',
890 890 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
891 891 controller='compare', action='compare',
892 892 conditions={'function': check_repo},
893 893 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
894 894
895 895 rmap.connect('pullrequest_home',
896 896 '/{repo_name}/pull-request/new', controller='pullrequests',
897 897 action='index', conditions={'function': check_repo,
898 898 'method': ['GET']},
899 899 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
900 900
901 901 rmap.connect('pullrequest',
902 902 '/{repo_name}/pull-request/new', controller='pullrequests',
903 903 action='create', conditions={'function': check_repo,
904 904 'method': ['POST']},
905 905 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
906 906
907 907 rmap.connect('pullrequest_repo_refs',
908 908 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
909 909 controller='pullrequests',
910 910 action='get_repo_refs',
911 911 conditions={'function': check_repo, 'method': ['GET']},
912 912 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
913 913
914 914 rmap.connect('pullrequest_repo_destinations',
915 915 '/{repo_name}/pull-request/repo-destinations',
916 916 controller='pullrequests',
917 917 action='get_repo_destinations',
918 918 conditions={'function': check_repo, 'method': ['GET']},
919 919 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
920 920
921 921 rmap.connect('pullrequest_show',
922 922 '/{repo_name}/pull-request/{pull_request_id}',
923 923 controller='pullrequests',
924 924 action='show', conditions={'function': check_repo,
925 925 'method': ['GET']},
926 926 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
927 927
928 928 rmap.connect('pullrequest_update',
929 929 '/{repo_name}/pull-request/{pull_request_id}',
930 930 controller='pullrequests',
931 931 action='update', conditions={'function': check_repo,
932 932 'method': ['PUT']},
933 933 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
934 934
935 935 rmap.connect('pullrequest_merge',
936 936 '/{repo_name}/pull-request/{pull_request_id}',
937 937 controller='pullrequests',
938 938 action='merge', conditions={'function': check_repo,
939 939 'method': ['POST']},
940 940 requirements=URL_NAME_REQUIREMENTS)
941 941
942 942 rmap.connect('pullrequest_delete',
943 943 '/{repo_name}/pull-request/{pull_request_id}',
944 944 controller='pullrequests',
945 945 action='delete', conditions={'function': check_repo,
946 946 'method': ['DELETE']},
947 947 requirements=URL_NAME_REQUIREMENTS)
948 948
949 949 rmap.connect('pullrequest_show_all',
950 950 '/{repo_name}/pull-request',
951 951 controller='pullrequests',
952 952 action='show_all', conditions={'function': check_repo,
953 953 'method': ['GET']},
954 954 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
955 955
956 956 rmap.connect('pullrequest_comment',
957 957 '/{repo_name}/pull-request-comment/{pull_request_id}',
958 958 controller='pullrequests',
959 959 action='comment', conditions={'function': check_repo,
960 960 'method': ['POST']},
961 961 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
962 962
963 963 rmap.connect('pullrequest_comment_delete',
964 964 '/{repo_name}/pull-request-comment/{comment_id}/delete',
965 965 controller='pullrequests', action='delete_comment',
966 966 conditions={'function': check_repo, 'method': ['DELETE']},
967 967 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
968 968
969 969 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
970 970 controller='summary', conditions={'function': check_repo},
971 971 requirements=URL_NAME_REQUIREMENTS)
972 972
973 973 rmap.connect('branches_home', '/{repo_name}/branches',
974 974 controller='branches', conditions={'function': check_repo},
975 975 requirements=URL_NAME_REQUIREMENTS)
976 976
977 977 rmap.connect('tags_home', '/{repo_name}/tags',
978 978 controller='tags', conditions={'function': check_repo},
979 979 requirements=URL_NAME_REQUIREMENTS)
980 980
981 981 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
982 982 controller='bookmarks', conditions={'function': check_repo},
983 983 requirements=URL_NAME_REQUIREMENTS)
984 984
985 985 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
986 986 controller='changelog', conditions={'function': check_repo},
987 987 requirements=URL_NAME_REQUIREMENTS)
988 988
989 989 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
990 990 controller='changelog', action='changelog_summary',
991 991 conditions={'function': check_repo},
992 992 requirements=URL_NAME_REQUIREMENTS)
993 993
994 994 rmap.connect('changelog_file_home',
995 995 '/{repo_name}/changelog/{revision}/{f_path}',
996 996 controller='changelog', f_path=None,
997 997 conditions={'function': check_repo},
998 998 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
999 999
1000 rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}',
1001 controller='changelog', action='changelog_details',
1000 rmap.connect('changelog_elements', '/{repo_name}/changelog_details',
1001 controller='changelog', action='changelog_elements',
1002 1002 conditions={'function': check_repo},
1003 requirements=URL_NAME_REQUIREMENTS)
1003 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1004 1004
1005 1005 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
1006 1006 controller='files', revision='tip', f_path='',
1007 1007 conditions={'function': check_repo},
1008 1008 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1009 1009
1010 1010 rmap.connect('files_home_simple_catchrev',
1011 1011 '/{repo_name}/files/{revision}',
1012 1012 controller='files', revision='tip', f_path='',
1013 1013 conditions={'function': check_repo},
1014 1014 requirements=URL_NAME_REQUIREMENTS)
1015 1015
1016 1016 rmap.connect('files_home_simple_catchall',
1017 1017 '/{repo_name}/files',
1018 1018 controller='files', revision='tip', f_path='',
1019 1019 conditions={'function': check_repo},
1020 1020 requirements=URL_NAME_REQUIREMENTS)
1021 1021
1022 1022 rmap.connect('files_history_home',
1023 1023 '/{repo_name}/history/{revision}/{f_path}',
1024 1024 controller='files', action='history', revision='tip', f_path='',
1025 1025 conditions={'function': check_repo},
1026 1026 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1027 1027
1028 1028 rmap.connect('files_authors_home',
1029 1029 '/{repo_name}/authors/{revision}/{f_path}',
1030 1030 controller='files', action='authors', revision='tip', f_path='',
1031 1031 conditions={'function': check_repo},
1032 1032 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1033 1033
1034 1034 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
1035 1035 controller='files', action='diff', f_path='',
1036 1036 conditions={'function': check_repo},
1037 1037 requirements=URL_NAME_REQUIREMENTS)
1038 1038
1039 1039 rmap.connect('files_diff_2way_home',
1040 1040 '/{repo_name}/diff-2way/{f_path}',
1041 1041 controller='files', action='diff_2way', f_path='',
1042 1042 conditions={'function': check_repo},
1043 1043 requirements=URL_NAME_REQUIREMENTS)
1044 1044
1045 1045 rmap.connect('files_rawfile_home',
1046 1046 '/{repo_name}/rawfile/{revision}/{f_path}',
1047 1047 controller='files', action='rawfile', revision='tip',
1048 1048 f_path='', conditions={'function': check_repo},
1049 1049 requirements=URL_NAME_REQUIREMENTS)
1050 1050
1051 1051 rmap.connect('files_raw_home',
1052 1052 '/{repo_name}/raw/{revision}/{f_path}',
1053 1053 controller='files', action='raw', revision='tip', f_path='',
1054 1054 conditions={'function': check_repo},
1055 1055 requirements=URL_NAME_REQUIREMENTS)
1056 1056
1057 1057 rmap.connect('files_render_home',
1058 1058 '/{repo_name}/render/{revision}/{f_path}',
1059 1059 controller='files', action='index', revision='tip', f_path='',
1060 1060 rendered=True, conditions={'function': check_repo},
1061 1061 requirements=URL_NAME_REQUIREMENTS)
1062 1062
1063 1063 rmap.connect('files_annotate_home',
1064 1064 '/{repo_name}/annotate/{revision}/{f_path}',
1065 1065 controller='files', action='index', revision='tip',
1066 1066 f_path='', annotate=True, conditions={'function': check_repo},
1067 1067 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1068 1068
1069 1069 rmap.connect('files_edit',
1070 1070 '/{repo_name}/edit/{revision}/{f_path}',
1071 1071 controller='files', action='edit', revision='tip',
1072 1072 f_path='',
1073 1073 conditions={'function': check_repo, 'method': ['POST']},
1074 1074 requirements=URL_NAME_REQUIREMENTS)
1075 1075
1076 1076 rmap.connect('files_edit_home',
1077 1077 '/{repo_name}/edit/{revision}/{f_path}',
1078 1078 controller='files', action='edit_home', revision='tip',
1079 1079 f_path='', conditions={'function': check_repo},
1080 1080 requirements=URL_NAME_REQUIREMENTS)
1081 1081
1082 1082 rmap.connect('files_add',
1083 1083 '/{repo_name}/add/{revision}/{f_path}',
1084 1084 controller='files', action='add', revision='tip',
1085 1085 f_path='',
1086 1086 conditions={'function': check_repo, 'method': ['POST']},
1087 1087 requirements=URL_NAME_REQUIREMENTS)
1088 1088
1089 1089 rmap.connect('files_add_home',
1090 1090 '/{repo_name}/add/{revision}/{f_path}',
1091 1091 controller='files', action='add_home', revision='tip',
1092 1092 f_path='', conditions={'function': check_repo},
1093 1093 requirements=URL_NAME_REQUIREMENTS)
1094 1094
1095 1095 rmap.connect('files_delete',
1096 1096 '/{repo_name}/delete/{revision}/{f_path}',
1097 1097 controller='files', action='delete', revision='tip',
1098 1098 f_path='',
1099 1099 conditions={'function': check_repo, 'method': ['POST']},
1100 1100 requirements=URL_NAME_REQUIREMENTS)
1101 1101
1102 1102 rmap.connect('files_delete_home',
1103 1103 '/{repo_name}/delete/{revision}/{f_path}',
1104 1104 controller='files', action='delete_home', revision='tip',
1105 1105 f_path='', conditions={'function': check_repo},
1106 1106 requirements=URL_NAME_REQUIREMENTS)
1107 1107
1108 1108 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1109 1109 controller='files', action='archivefile',
1110 1110 conditions={'function': check_repo},
1111 1111 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1112 1112
1113 1113 rmap.connect('files_nodelist_home',
1114 1114 '/{repo_name}/nodelist/{revision}/{f_path}',
1115 1115 controller='files', action='nodelist',
1116 1116 conditions={'function': check_repo},
1117 1117 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1118 1118
1119 1119 rmap.connect('files_nodetree_full',
1120 1120 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1121 1121 controller='files', action='nodetree_full',
1122 1122 conditions={'function': check_repo},
1123 1123 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1124 1124
1125 1125 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1126 1126 controller='forks', action='fork_create',
1127 1127 conditions={'function': check_repo, 'method': ['POST']},
1128 1128 requirements=URL_NAME_REQUIREMENTS)
1129 1129
1130 1130 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1131 1131 controller='forks', action='fork',
1132 1132 conditions={'function': check_repo},
1133 1133 requirements=URL_NAME_REQUIREMENTS)
1134 1134
1135 1135 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1136 1136 controller='forks', action='forks',
1137 1137 conditions={'function': check_repo},
1138 1138 requirements=URL_NAME_REQUIREMENTS)
1139 1139
1140 1140 rmap.connect('repo_followers_home', '/{repo_name}/followers',
1141 1141 controller='followers', action='followers',
1142 1142 conditions={'function': check_repo},
1143 1143 requirements=URL_NAME_REQUIREMENTS)
1144 1144
1145 1145 # must be here for proper group/repo catching pattern
1146 1146 _connect_with_slash(
1147 1147 rmap, 'repo_group_home', '/{group_name}',
1148 1148 controller='home', action='index_repo_group',
1149 1149 conditions={'function': check_group},
1150 1150 requirements=URL_NAME_REQUIREMENTS)
1151 1151
1152 1152 # catch all, at the end
1153 1153 _connect_with_slash(
1154 1154 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1155 1155 controller='summary', action='index',
1156 1156 conditions={'function': check_repo},
1157 1157 requirements=URL_NAME_REQUIREMENTS)
1158 1158
1159 1159 return rmap
1160 1160
1161 1161
1162 1162 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1163 1163 """
1164 1164 Connect a route with an optional trailing slash in `path`.
1165 1165 """
1166 1166 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1167 1167 mapper.connect(name, path, *args, **kwargs)
@@ -1,222 +1,290 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 changelog controller for rhodecode
23 23 """
24 24
25 25 import logging
26 26
27 27 from pylons import request, url, session, tmpl_context as c
28 28 from pylons.controllers.util import redirect
29 29 from pylons.i18n.translation import _
30 30 from webob.exc import HTTPNotFound, HTTPBadRequest
31 31
32 32 import rhodecode.lib.helpers as h
33 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
33 from rhodecode.lib.auth import (
34 LoginRequired, HasRepoPermissionAnyDecorator, XHRRequired)
34 35 from rhodecode.lib.base import BaseRepoController, render
35 36 from rhodecode.lib.ext_json import json
36 37 from rhodecode.lib.graphmod import _colored, _dagwalker
37 38 from rhodecode.lib.helpers import RepoPage
38 39 from rhodecode.lib.utils2 import safe_int, safe_str
39 40 from rhodecode.lib.vcs.exceptions import (
40 41 RepositoryError, CommitDoesNotExistError,
41 42 CommitError, NodeDoesNotExistError, EmptyRepositoryError)
42 43
43 44 log = logging.getLogger(__name__)
44 45
45 46 DEFAULT_CHANGELOG_SIZE = 20
46 47
47 48
48 49 def _load_changelog_summary():
49 50 p = safe_int(request.GET.get('page'), 1)
50 51 size = safe_int(request.GET.get('size'), 10)
51 52
52 53 def url_generator(**kw):
53 54 return url('summary_home',
54 55 repo_name=c.rhodecode_db_repo.repo_name, size=size, **kw)
55 56
56 57 pre_load = ['author', 'branch', 'date', 'message']
57 58 try:
58 59 collection = c.rhodecode_repo.get_commits(pre_load=pre_load)
59 60 except EmptyRepositoryError:
60 61 collection = c.rhodecode_repo
61 62
62 63 c.repo_commits = RepoPage(
63 64 collection, page=p, items_per_page=size, url=url_generator)
64 65 page_ids = [x.raw_id for x in c.repo_commits]
65 66 c.comments = c.rhodecode_db_repo.get_comments(page_ids)
66 67 c.statuses = c.rhodecode_db_repo.statuses(page_ids)
67 68
68 69
69 70 class ChangelogController(BaseRepoController):
70 71
71 72 def __before__(self):
72 73 super(ChangelogController, self).__before__()
73 74 c.affected_files_cut_off = 60
74 75
75 76 def __get_commit_or_redirect(
76 77 self, commit_id, repo, redirect_after=True, partial=False):
77 78 """
78 79 This is a safe way to get a commit. If an error occurs it
79 80 redirects to a commit with a proper message. If partial is set
80 81 then it does not do redirect raise and throws an exception instead.
81 82
82 83 :param commit_id: commit to fetch
83 84 :param repo: repo instance
84 85 """
85 86 try:
86 87 return c.rhodecode_repo.get_commit(commit_id)
87 88 except EmptyRepositoryError:
88 89 if not redirect_after:
89 90 return None
90 91 h.flash(h.literal(_('There are no commits yet')),
91 92 category='warning')
92 93 redirect(url('changelog_home', repo_name=repo.repo_name))
93 94 except RepositoryError as e:
94 95 msg = safe_str(e)
95 96 log.exception(msg)
96 97 h.flash(msg, category='warning')
97 98 if not partial:
98 99 redirect(h.url('changelog_home', repo_name=repo.repo_name))
99 100 raise HTTPBadRequest()
100 101
101 def _graph(self, repo, commits):
102 def _graph(self, repo, commits, prev_data=None, next_data=None):
102 103 """
103 104 Generates a DAG graph for repo
104 105
105 106 :param repo: repo instance
106 107 :param commits: list of commits
107 108 """
108 109 if not commits:
109 c.jsdata = json.dumps([])
110 return
110 return json.dumps([])
111
112 def serialize(commit, parents=True):
113 data = dict(
114 raw_id=commit.raw_id,
115 idx=commit.idx,
116 branch=commit.branch,
117 )
118 if parents:
119 data['parents'] = [
120 serialize(x, parents=False) for x in commit.parents]
121 return data
122
123 prev_data = prev_data or []
124 next_data = next_data or []
125
126 current = [serialize(x) for x in commits]
127 commits = prev_data + current + next_data
111 128
112 129 dag = _dagwalker(repo, commits)
113 data = [['', vtx, edges] for vtx, edges in _colored(dag)]
114 c.jsdata = json.dumps(data)
130
131 data = [[commit_id, vtx, edges, branch]
132 for commit_id, vtx, edges, branch in _colored(dag)]
133 return json.dumps(data), json.dumps(current)
115 134
116 135 def _check_if_valid_branch(self, branch_name, repo_name, f_path):
117 136 if branch_name not in c.rhodecode_repo.branches_all:
118 137 h.flash('Branch {} is not found.'.format(branch_name),
119 138 category='warning')
120 139 redirect(url('changelog_file_home', repo_name=repo_name,
121 140 revision=branch_name, f_path=f_path or ''))
122 141
142 def _load_changelog_data(self, collection, page, chunk_size, branch_name=None, dynamic=False):
143 c.total_cs = len(collection)
144 c.showing_commits = min(chunk_size, c.total_cs)
145 c.pagination = RepoPage(collection, page=page, item_count=c.total_cs,
146 items_per_page=chunk_size, branch=branch_name)
147
148 c.next_page = c.pagination.next_page
149 c.prev_page = c.pagination.previous_page
150
151 if dynamic:
152 if request.GET.get('chunk') != 'next':
153 c.next_page = None
154 if request.GET.get('chunk') != 'prev':
155 c.prev_page = None
156
157 page_commit_ids = [x.raw_id for x in c.pagination]
158 c.comments = c.rhodecode_db_repo.get_comments(page_commit_ids)
159 c.statuses = c.rhodecode_db_repo.statuses(page_commit_ids)
160
123 161 @LoginRequired()
124 162 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
125 163 'repository.admin')
126 164 def index(self, repo_name, revision=None, f_path=None):
127 165 commit_id = revision
128 limit = 100
166 chunk_size = 20
167
168 c.branch_name = branch_name = request.GET.get('branch', None)
169 c.book_name = book_name = request.GET.get('bookmark', None)
129 170 hist_limit = safe_int(request.GET.get('limit')) or None
130 if request.GET.get('size'):
131 c.size = safe_int(request.GET.get('size'), 1)
132 session['changelog_size'] = c.size
133 session.save()
134 else:
135 c.size = int(session.get('changelog_size', DEFAULT_CHANGELOG_SIZE))
136
137 # min size must be 1 and less than limit
138 c.size = max(c.size, 1) if c.size <= limit else limit
139 171
140 172 p = safe_int(request.GET.get('page', 1), 1)
141 c.branch_name = branch_name = request.GET.get('branch', None)
142 c.book_name = book_name = request.GET.get('bookmark', None)
143 173
144 174 c.selected_name = branch_name or book_name
145 175 if not commit_id and branch_name:
146 176 self._check_if_valid_branch(branch_name, repo_name, f_path)
147 177
148 178 c.changelog_for_path = f_path
149 179 pre_load = ['author', 'branch', 'date', 'message', 'parents']
180 commit_ids = []
181
150 182 try:
151 183 if f_path:
152 184 log.debug('generating changelog for path %s', f_path)
153 185 # get the history for the file !
154 186 base_commit = c.rhodecode_repo.get_commit(revision)
155 187 try:
156 188 collection = base_commit.get_file_history(
157 189 f_path, limit=hist_limit, pre_load=pre_load)
158 190 if (collection
159 191 and request.environ.get('HTTP_X_PARTIAL_XHR')):
160 192 # for ajax call we remove first one since we're looking
161 193 # at it right now in the context of a file commit
162 194 collection.pop(0)
163 195 except (NodeDoesNotExistError, CommitError):
164 196 # this node is not present at tip!
165 197 try:
166 198 commit = self.__get_commit_or_redirect(
167 199 commit_id, repo_name)
168 200 collection = commit.get_file_history(f_path)
169 201 except RepositoryError as e:
170 202 h.flash(safe_str(e), category='warning')
171 203 redirect(h.url('changelog_home', repo_name=repo_name))
172 204 collection = list(reversed(collection))
173 205 else:
174 206 collection = c.rhodecode_repo.get_commits(
175 207 branch_name=branch_name, pre_load=pre_load)
176 208
177 c.total_cs = len(collection)
178 c.showing_commits = min(c.size, c.total_cs)
179 c.pagination = RepoPage(collection, page=p, item_count=c.total_cs,
180 items_per_page=c.size, branch=branch_name)
181 page_commit_ids = [x.raw_id for x in c.pagination]
182 c.comments = c.rhodecode_db_repo.get_comments(page_commit_ids)
183 c.statuses = c.rhodecode_db_repo.statuses(page_commit_ids)
209 self._load_changelog_data(
210 collection, p, chunk_size, c.branch_name, dynamic=f_path)
211
184 212 except EmptyRepositoryError as e:
185 213 h.flash(safe_str(e), category='warning')
186 214 return redirect(url('summary_home', repo_name=repo_name))
187 215 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
188 216 msg = safe_str(e)
189 217 log.exception(msg)
190 218 h.flash(msg, category='error')
191 219 return redirect(url('changelog_home', repo_name=repo_name))
192 220
193 221 if (request.environ.get('HTTP_X_PARTIAL_XHR')
194 222 or request.environ.get('HTTP_X_PJAX')):
195 223 # loading from ajax, we don't want the first result, it's popped
196 224 return render('changelog/changelog_file_history.mako')
197 225
198 if f_path:
199 revs = []
200 else:
201 revs = c.pagination
202 self._graph(c.rhodecode_repo, revs)
226 if not f_path:
227 commit_ids = c.pagination
228
229 c.graph_data, c.graph_commits = self._graph(
230 c.rhodecode_repo, commit_ids)
203 231
204 232 return render('changelog/changelog.mako')
205 233
206 234 @LoginRequired()
207 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
208 'repository.admin')
209 def changelog_details(self, commit_id):
210 if request.environ.get('HTTP_X_PARTIAL_XHR'):
211 c.commit = c.rhodecode_repo.get_commit(commit_id=commit_id)
212 return render('changelog/changelog_details.mako')
213 raise HTTPNotFound()
235 @XHRRequired()
236 @HasRepoPermissionAnyDecorator(
237 'repository.read', 'repository.write', 'repository.admin')
238 def changelog_elements(self, repo_name):
239 commit_id = None
240 chunk_size = 20
241
242 def wrap_for_error(err):
243 return '<tr><td colspan="9" class="alert alert-error">ERROR: {}</td></tr>'.format(err)
244
245 c.branch_name = branch_name = request.GET.get('branch', None)
246 c.book_name = book_name = request.GET.get('bookmark', None)
247
248 p = safe_int(request.GET.get('page', 1), 1)
249
250 c.selected_name = branch_name or book_name
251 if not commit_id and branch_name:
252 if branch_name not in c.rhodecode_repo.branches_all:
253 return wrap_for_error(
254 safe_str('Missing branch: {}'.format(branch_name)))
255
256 pre_load = ['author', 'branch', 'date', 'message', 'parents']
257 collection = c.rhodecode_repo.get_commits(
258 branch_name=branch_name, pre_load=pre_load)
259
260 try:
261 self._load_changelog_data(collection, p, chunk_size, dynamic=True)
262 except EmptyRepositoryError as e:
263 return wrap_for_error(safe_str(e))
264 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
265 log.exception('Failed to fetch commits')
266 return wrap_for_error(safe_str(e))
267
268 prev_data = None
269 next_data = None
270
271 prev_graph = json.loads(request.POST.get('graph', ''))
272
273 if request.GET.get('chunk') == 'prev':
274 next_data = prev_graph
275 elif request.GET.get('chunk') == 'next':
276 prev_data = prev_graph
277
278 c.graph_data, c.graph_commits = self._graph(
279 c.rhodecode_repo, c.pagination,
280 prev_data=prev_data, next_data=next_data)
281 return render('changelog/changelog_elements.mako')
214 282
215 283 @LoginRequired()
216 284 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
217 285 'repository.admin')
218 286 def changelog_summary(self, repo_name):
219 287 if request.environ.get('HTTP_X_PJAX'):
220 288 _load_changelog_summary()
221 289 return render('changelog/changelog_summary_data.mako')
222 290 raise HTTPNotFound()
@@ -1,148 +1,142 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 """
22 22 Modified mercurial DAG graph functions that re-uses VCS structure
23 23
24 It allows to have a shared codebase for DAG generation for hg and git repos
24 It allows to have a shared codebase for DAG generation for hg, git, svn repos
25 25 """
26 26
27 27 nullrev = -1
28 28
29 29
30 30 def grandparent(parent_idx_func, lowest_idx, roots, head):
31 31 """
32 32 Return all ancestors of head in roots which commit is
33 33 greater or equal to lowest_idx.
34 34 """
35 35 pending = set([head])
36 36 seen = set()
37 37 kept = set()
38 38 llowestrev = max(nullrev, lowest_idx)
39 39 while pending:
40 40 r = pending.pop()
41 41 if r >= llowestrev and r not in seen:
42 42 if r in roots:
43 43 kept.add(r)
44 44 else:
45 45 pending.update(parent_idx_func(r))
46 46 seen.add(r)
47 47 return sorted(kept)
48 48
49 49
50 50 def _dagwalker(repo, commits):
51 51 if not commits:
52 52 return
53 53
54 # TODO: johbo: Use some sort of vcs api here
55 if repo.alias == 'hg':
56 def get_parent_indexes(idx):
57 return repo._remote.ctx_parents(idx)
54 def get_parent_indexes(idx):
55 return [commit.idx for commit in repo[idx].parents]
58 56
59 elif repo.alias in ['git', 'svn']:
60 def get_parent_indexes(idx):
61 return [commit.idx for commit in repo[idx].parents]
62
63 indexes = [commit.idx for commit in commits]
57 indexes = [commit['idx'] for commit in commits]
64 58 lowest_idx = min(indexes)
65 59 known_indexes = set(indexes)
66 60
67 gpcache = {}
61 grandparnet_cache = {}
68 62 for commit in commits:
69 parents = sorted(set([p.idx for p in commit.parents
70 if p.idx in known_indexes]))
71 mpars = [p.idx for p in commit.parents if
72 p.idx != nullrev and p.idx not in parents]
63 parents = sorted(set([p['idx'] for p in commit['parents']
64 if p['idx'] in known_indexes]))
65 mpars = [p['idx'] for p in commit['parents'] if
66 p['idx'] != nullrev and p['idx'] not in parents]
73 67 for mpar in mpars:
74 gp = gpcache.get(mpar)
68 gp = grandparnet_cache.get(mpar)
75 69 if gp is None:
76 gp = gpcache[mpar] = grandparent(
70 gp = grandparnet_cache[mpar] = grandparent(
77 71 get_parent_indexes, lowest_idx, indexes, mpar)
78 72 if not gp:
79 73 parents.append(mpar)
80 74 else:
81 75 parents.extend(g for g in gp if g not in parents)
82 76
83 yield (commit.idx, parents)
77 yield (commit['raw_id'], commit['idx'], parents, commit['branch'])
84 78
85 79
86 80 def _colored(dag):
87 81 """annotates a DAG with colored edge information
88 82
89 83 For each DAG node this function emits tuples::
90 84
91 85 ((col, color), [(col, nextcol, color)])
92 86
93 87 with the following new elements:
94 88
95 89 - Tuple (col, color) with column and color index for the current node
96 90 - A list of tuples indicating the edges between the current node and its
97 91 parents.
98 92 """
99 93 seen = []
100 94 colors = {}
101 95 newcolor = 1
102 96
103 for commit_idx, parents in dag:
97 for commit_id, commit_idx, parents, branch in dag:
104 98
105 99 # Compute seen and next_
106 100 if commit_idx not in seen:
107 101 seen.append(commit_idx) # new head
108 102 colors[commit_idx] = newcolor
109 103 newcolor += 1
110 104
111 105 col = seen.index(commit_idx)
112 106 color = colors.pop(commit_idx)
113 107 next_ = seen[:]
114 108
115 109 # Add parents to next_
116 110 addparents = [p for p in parents if p not in next_]
117 111 next_[col:col + 1] = addparents
118 112
119 113 # Set colors for the parents
120 114 for i, p in enumerate(addparents):
121 115 if i == 0:
122 116 colors[p] = color
123 117 else:
124 118 colors[p] = newcolor
125 119 newcolor += 1
126 120
127 121 # Add edges to the graph
128 122 edges = []
129 123 for ecol, eid in enumerate(seen):
130 124 if eid in next_:
131 125 edges.append((ecol, next_.index(eid), colors[eid]))
132 126 elif eid == commit_idx:
133 127 total_parents = len(parents)
134 128 edges.extend([
135 129 (ecol, next_.index(p),
136 130 _get_edge_color(p, total_parents, color, colors))
137 131 for p in parents])
138 132
139 133 # Yield and move on
140 yield ((col, color), edges)
134 yield (commit_id, (col, color), edges, branch)
141 135 seen = next_
142 136
143 137
144 138 def _get_edge_color(parent, total_parents, color, colors):
145 139 if total_parents <= 1:
146 140 return color
147 141
148 142 return colors.get(parent, color)
@@ -1,2337 +1,2349 b''
1 1 //Primary CSS
2 2
3 3 //--- IMPORTS ------------------//
4 4
5 5 @import 'helpers';
6 6 @import 'mixins';
7 7 @import 'rcicons';
8 8 @import 'fonts';
9 9 @import 'variables';
10 10 @import 'bootstrap-variables';
11 11 @import 'form-bootstrap';
12 12 @import 'codemirror';
13 13 @import 'legacy_code_styles';
14 14 @import 'progress-bar';
15 15
16 16 @import 'type';
17 17 @import 'alerts';
18 18 @import 'buttons';
19 19 @import 'tags';
20 20 @import 'code-block';
21 21 @import 'examples';
22 22 @import 'login';
23 23 @import 'main-content';
24 24 @import 'select2';
25 25 @import 'comments';
26 26 @import 'panels-bootstrap';
27 27 @import 'panels';
28 28 @import 'deform';
29 29
30 30 //--- BASE ------------------//
31 31 .noscript-error {
32 32 top: 0;
33 33 left: 0;
34 34 width: 100%;
35 35 z-index: 101;
36 36 text-align: center;
37 37 font-family: @text-semibold;
38 38 font-size: 120%;
39 39 color: white;
40 40 background-color: @alert2;
41 41 padding: 5px 0 5px 0;
42 42 }
43 43
44 44 html {
45 45 display: table;
46 46 height: 100%;
47 47 width: 100%;
48 48 }
49 49
50 50 body {
51 51 display: table-cell;
52 52 width: 100%;
53 53 }
54 54
55 55 //--- LAYOUT ------------------//
56 56
57 57 .hidden{
58 58 display: none !important;
59 59 }
60 60
61 61 .box{
62 62 float: left;
63 63 width: 100%;
64 64 }
65 65
66 66 .browser-header {
67 67 clear: both;
68 68 }
69 69 .main {
70 70 clear: both;
71 71 padding:0 0 @pagepadding;
72 72 height: auto;
73 73
74 74 &:after { //clearfix
75 75 content:"";
76 76 clear:both;
77 77 width:100%;
78 78 display:block;
79 79 }
80 80 }
81 81
82 82 .action-link{
83 83 margin-left: @padding;
84 84 padding-left: @padding;
85 85 border-left: @border-thickness solid @border-default-color;
86 86 }
87 87
88 88 input + .action-link, .action-link.first{
89 89 border-left: none;
90 90 }
91 91
92 92 .action-link.last{
93 93 margin-right: @padding;
94 94 padding-right: @padding;
95 95 }
96 96
97 97 .action-link.active,
98 98 .action-link.active a{
99 99 color: @grey4;
100 100 }
101 101
102 102 ul.simple-list{
103 103 list-style: none;
104 104 margin: 0;
105 105 padding: 0;
106 106 }
107 107
108 108 .main-content {
109 109 padding-bottom: @pagepadding;
110 110 }
111 111
112 112 .wide-mode-wrapper {
113 113 max-width:4000px !important;
114 114 }
115 115
116 116 .wrapper {
117 117 position: relative;
118 118 max-width: @wrapper-maxwidth;
119 119 margin: 0 auto;
120 120 }
121 121
122 122 #content {
123 123 clear: both;
124 124 padding: 0 @contentpadding;
125 125 }
126 126
127 127 .advanced-settings-fields{
128 128 input{
129 129 margin-left: @textmargin;
130 130 margin-right: @padding/2;
131 131 }
132 132 }
133 133
134 134 .cs_files_title {
135 135 margin: @pagepadding 0 0;
136 136 }
137 137
138 138 input.inline[type="file"] {
139 139 display: inline;
140 140 }
141 141
142 142 .error_page {
143 143 margin: 10% auto;
144 144
145 145 h1 {
146 146 color: @grey2;
147 147 }
148 148
149 149 .alert {
150 150 margin: @padding 0;
151 151 }
152 152
153 153 .error-branding {
154 154 font-family: @text-semibold;
155 155 color: @grey4;
156 156 }
157 157
158 158 .error_message {
159 159 font-family: @text-regular;
160 160 }
161 161
162 162 .sidebar {
163 163 min-height: 275px;
164 164 margin: 0;
165 165 padding: 0 0 @sidebarpadding @sidebarpadding;
166 166 border: none;
167 167 }
168 168
169 169 .main-content {
170 170 position: relative;
171 171 margin: 0 @sidebarpadding @sidebarpadding;
172 172 padding: 0 0 0 @sidebarpadding;
173 173 border-left: @border-thickness solid @grey5;
174 174
175 175 @media (max-width:767px) {
176 176 clear: both;
177 177 width: 100%;
178 178 margin: 0;
179 179 border: none;
180 180 }
181 181 }
182 182
183 183 .inner-column {
184 184 float: left;
185 185 width: 29.75%;
186 186 min-height: 150px;
187 187 margin: @sidebarpadding 2% 0 0;
188 188 padding: 0 2% 0 0;
189 189 border-right: @border-thickness solid @grey5;
190 190
191 191 @media (max-width:767px) {
192 192 clear: both;
193 193 width: 100%;
194 194 border: none;
195 195 }
196 196
197 197 ul {
198 198 padding-left: 1.25em;
199 199 }
200 200
201 201 &:last-child {
202 202 margin: @sidebarpadding 0 0;
203 203 border: none;
204 204 }
205 205
206 206 h4 {
207 207 margin: 0 0 @padding;
208 208 font-family: @text-semibold;
209 209 }
210 210 }
211 211 }
212 212 .error-page-logo {
213 213 width: 130px;
214 214 height: 160px;
215 215 }
216 216
217 217 // HEADER
218 218 .header {
219 219
220 220 // TODO: johbo: Fix login pages, so that they work without a min-height
221 221 // for the header and then remove the min-height. I chose a smaller value
222 222 // intentionally here to avoid rendering issues in the main navigation.
223 223 min-height: 49px;
224 224
225 225 position: relative;
226 226 vertical-align: bottom;
227 227 padding: 0 @header-padding;
228 228 background-color: @grey2;
229 229 color: @grey5;
230 230
231 231 .title {
232 232 overflow: visible;
233 233 }
234 234
235 235 &:before,
236 236 &:after {
237 237 content: "";
238 238 clear: both;
239 239 width: 100%;
240 240 }
241 241
242 242 // TODO: johbo: Avoids breaking "Repositories" chooser
243 243 .select2-container .select2-choice .select2-arrow {
244 244 display: none;
245 245 }
246 246 }
247 247
248 248 #header-inner {
249 249 &.title {
250 250 margin: 0;
251 251 }
252 252 &:before,
253 253 &:after {
254 254 content: "";
255 255 clear: both;
256 256 }
257 257 }
258 258
259 259 // Gists
260 260 #files_data {
261 261 clear: both; //for firefox
262 262 }
263 263 #gistid {
264 264 margin-right: @padding;
265 265 }
266 266
267 267 // Global Settings Editor
268 268 .textarea.editor {
269 269 float: left;
270 270 position: relative;
271 271 max-width: @texteditor-width;
272 272
273 273 select {
274 274 position: absolute;
275 275 top:10px;
276 276 right:0;
277 277 }
278 278
279 279 .CodeMirror {
280 280 margin: 0;
281 281 }
282 282
283 283 .help-block {
284 284 margin: 0 0 @padding;
285 285 padding:.5em;
286 286 background-color: @grey6;
287 287 }
288 288 }
289 289
290 290 ul.auth_plugins {
291 291 margin: @padding 0 @padding @legend-width;
292 292 padding: 0;
293 293
294 294 li {
295 295 margin-bottom: @padding;
296 296 line-height: 1em;
297 297 list-style-type: none;
298 298
299 299 .auth_buttons .btn {
300 300 margin-right: @padding;
301 301 }
302 302
303 303 &:before { content: none; }
304 304 }
305 305 }
306 306
307 307
308 308 // My Account PR list
309 309
310 310 #show_closed {
311 311 margin: 0 1em 0 0;
312 312 }
313 313
314 314 .pullrequestlist {
315 315 .closed {
316 316 background-color: @grey6;
317 317 }
318 318 .td-status {
319 319 padding-left: .5em;
320 320 }
321 321 .log-container .truncate {
322 322 height: 2.75em;
323 323 white-space: pre-line;
324 324 }
325 325 table.rctable .user {
326 326 padding-left: 0;
327 327 }
328 328 table.rctable {
329 329 td.td-description,
330 330 .rc-user {
331 331 min-width: auto;
332 332 }
333 333 }
334 334 }
335 335
336 336 // Pull Requests
337 337
338 338 .pullrequests_section_head {
339 339 display: block;
340 340 clear: both;
341 341 margin: @padding 0;
342 342 font-family: @text-bold;
343 343 }
344 344
345 345 .pr-origininfo, .pr-targetinfo {
346 346 position: relative;
347 347
348 348 .tag {
349 349 display: inline-block;
350 350 margin: 0 1em .5em 0;
351 351 }
352 352
353 353 .clone-url {
354 354 display: inline-block;
355 355 margin: 0 0 .5em 0;
356 356 padding: 0;
357 357 line-height: 1.2em;
358 358 }
359 359 }
360 360
361 361 .pr-pullinfo {
362 362 clear: both;
363 363 margin: .5em 0;
364 364 }
365 365
366 366 #pr-title-input {
367 367 width: 72%;
368 368 font-size: 1em;
369 369 font-family: @text-bold;
370 370 margin: 0;
371 371 padding: 0 0 0 @padding/4;
372 372 line-height: 1.7em;
373 373 color: @text-color;
374 374 letter-spacing: .02em;
375 375 }
376 376
377 377 #pullrequest_title {
378 378 width: 100%;
379 379 box-sizing: border-box;
380 380 }
381 381
382 382 #pr_open_message {
383 383 border: @border-thickness solid #fff;
384 384 border-radius: @border-radius;
385 385 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
386 386 text-align: right;
387 387 overflow: hidden;
388 388 }
389 389
390 390 .pr-submit-button {
391 391 float: right;
392 392 margin: 0 0 0 5px;
393 393 }
394 394
395 395 .pr-spacing-container {
396 396 padding: 20px;
397 397 clear: both
398 398 }
399 399
400 400 #pr-description-input {
401 401 margin-bottom: 0;
402 402 }
403 403
404 404 .pr-description-label {
405 405 vertical-align: top;
406 406 }
407 407
408 408 .perms_section_head {
409 409 min-width: 625px;
410 410
411 411 h2 {
412 412 margin-bottom: 0;
413 413 }
414 414
415 415 .label-checkbox {
416 416 float: left;
417 417 }
418 418
419 419 &.field {
420 420 margin: @space 0 @padding;
421 421 }
422 422
423 423 &:first-child.field {
424 424 margin-top: 0;
425 425
426 426 .label {
427 427 margin-top: 0;
428 428 padding-top: 0;
429 429 }
430 430
431 431 .radios {
432 432 padding-top: 0;
433 433 }
434 434 }
435 435
436 436 .radios {
437 437 float: right;
438 438 position: relative;
439 439 width: 405px;
440 440 }
441 441 }
442 442
443 443 //--- MODULES ------------------//
444 444
445 445
446 446 // Server Announcement
447 447 #server-announcement {
448 448 width: 95%;
449 449 margin: @padding auto;
450 450 padding: @padding;
451 451 border-width: 2px;
452 452 border-style: solid;
453 453 .border-radius(2px);
454 454 font-family: @text-bold;
455 455
456 456 &.info { border-color: @alert4; background-color: @alert4-inner; }
457 457 &.warning { border-color: @alert3; background-color: @alert3-inner; }
458 458 &.error { border-color: @alert2; background-color: @alert2-inner; }
459 459 &.success { border-color: @alert1; background-color: @alert1-inner; }
460 460 &.neutral { border-color: @grey3; background-color: @grey6; }
461 461 }
462 462
463 463 // Fixed Sidebar Column
464 464 .sidebar-col-wrapper {
465 465 padding-left: @sidebar-all-width;
466 466
467 467 .sidebar {
468 468 width: @sidebar-width;
469 469 margin-left: -@sidebar-all-width;
470 470 }
471 471 }
472 472
473 473 .sidebar-col-wrapper.scw-small {
474 474 padding-left: @sidebar-small-all-width;
475 475
476 476 .sidebar {
477 477 width: @sidebar-small-width;
478 478 margin-left: -@sidebar-small-all-width;
479 479 }
480 480 }
481 481
482 482
483 483 // FOOTER
484 484 #footer {
485 485 padding: 0;
486 486 text-align: center;
487 487 vertical-align: middle;
488 488 color: @grey2;
489 489 background-color: @grey6;
490 490
491 491 p {
492 492 margin: 0;
493 493 padding: 1em;
494 494 line-height: 1em;
495 495 }
496 496
497 497 .server-instance { //server instance
498 498 display: none;
499 499 }
500 500
501 501 .title {
502 502 float: none;
503 503 margin: 0 auto;
504 504 }
505 505 }
506 506
507 507 button.close {
508 508 padding: 0;
509 509 cursor: pointer;
510 510 background: transparent;
511 511 border: 0;
512 512 .box-shadow(none);
513 513 -webkit-appearance: none;
514 514 }
515 515
516 516 .close {
517 517 float: right;
518 518 font-size: 21px;
519 519 font-family: @text-bootstrap;
520 520 line-height: 1em;
521 521 font-weight: bold;
522 522 color: @grey2;
523 523
524 524 &:hover,
525 525 &:focus {
526 526 color: @grey1;
527 527 text-decoration: none;
528 528 cursor: pointer;
529 529 }
530 530 }
531 531
532 532 // GRID
533 533 .sorting,
534 534 .sorting_desc,
535 535 .sorting_asc {
536 536 cursor: pointer;
537 537 }
538 538 .sorting_desc:after {
539 539 content: "\00A0\25B2";
540 540 font-size: .75em;
541 541 }
542 542 .sorting_asc:after {
543 543 content: "\00A0\25BC";
544 544 font-size: .68em;
545 545 }
546 546
547 547
548 548 .user_auth_tokens {
549 549
550 550 &.truncate {
551 551 white-space: nowrap;
552 552 overflow: hidden;
553 553 text-overflow: ellipsis;
554 554 }
555 555
556 556 .fields .field .input {
557 557 margin: 0;
558 558 }
559 559
560 560 input#description {
561 561 width: 100px;
562 562 margin: 0;
563 563 }
564 564
565 565 .drop-menu {
566 566 // TODO: johbo: Remove this, should work out of the box when
567 567 // having multiple inputs inline
568 568 margin: 0 0 0 5px;
569 569 }
570 570 }
571 571 #user_list_table {
572 572 .closed {
573 573 background-color: @grey6;
574 574 }
575 575 }
576 576
577 577
578 578 input {
579 579 &.disabled {
580 580 opacity: .5;
581 581 }
582 582 }
583 583
584 584 // remove extra padding in firefox
585 585 input::-moz-focus-inner { border:0; padding:0 }
586 586
587 587 .adjacent input {
588 588 margin-bottom: @padding;
589 589 }
590 590
591 591 .permissions_boxes {
592 592 display: block;
593 593 }
594 594
595 595 //TODO: lisa: this should be in tables
596 596 .show_more_col {
597 597 width: 20px;
598 598 }
599 599
600 600 //FORMS
601 601
602 602 .medium-inline,
603 603 input#description.medium-inline {
604 604 display: inline;
605 605 width: @medium-inline-input-width;
606 606 min-width: 100px;
607 607 }
608 608
609 609 select {
610 610 //reset
611 611 -webkit-appearance: none;
612 612 -moz-appearance: none;
613 613
614 614 display: inline-block;
615 615 height: 28px;
616 616 width: auto;
617 617 margin: 0 @padding @padding 0;
618 618 padding: 0 18px 0 8px;
619 619 line-height:1em;
620 620 font-size: @basefontsize;
621 621 border: @border-thickness solid @rcblue;
622 622 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
623 623 color: @rcblue;
624 624
625 625 &:after {
626 626 content: "\00A0\25BE";
627 627 }
628 628
629 629 &:focus {
630 630 outline: none;
631 631 }
632 632 }
633 633
634 634 option {
635 635 &:focus {
636 636 outline: none;
637 637 }
638 638 }
639 639
640 640 input,
641 641 textarea {
642 642 padding: @input-padding;
643 643 border: @input-border-thickness solid @border-highlight-color;
644 644 .border-radius (@border-radius);
645 645 font-family: @text-light;
646 646 font-size: @basefontsize;
647 647
648 648 &.input-sm {
649 649 padding: 5px;
650 650 }
651 651
652 652 &#description {
653 653 min-width: @input-description-minwidth;
654 654 min-height: 1em;
655 655 padding: 10px;
656 656 }
657 657 }
658 658
659 659 .field-sm {
660 660 input,
661 661 textarea {
662 662 padding: 5px;
663 663 }
664 664 }
665 665
666 666 textarea {
667 667 display: block;
668 668 clear: both;
669 669 width: 100%;
670 670 min-height: 100px;
671 671 margin-bottom: @padding;
672 672 .box-sizing(border-box);
673 673 overflow: auto;
674 674 }
675 675
676 676 label {
677 677 font-family: @text-light;
678 678 }
679 679
680 680 // GRAVATARS
681 681 // centers gravatar on username to the right
682 682
683 683 .gravatar {
684 684 display: inline;
685 685 min-width: 16px;
686 686 min-height: 16px;
687 687 margin: -5px 0;
688 688 padding: 0;
689 689 line-height: 1em;
690 690 border: 1px solid @grey4;
691 691 box-sizing: content-box;
692 692
693 693 &.gravatar-large {
694 694 margin: -0.5em .25em -0.5em 0;
695 695 }
696 696
697 697 & + .user {
698 698 display: inline;
699 699 margin: 0;
700 700 padding: 0 0 0 .17em;
701 701 line-height: 1em;
702 702 }
703 703 }
704 704
705 705 .user-inline-data {
706 706 display: inline-block;
707 707 float: left;
708 708 padding-left: .5em;
709 709 line-height: 1.3em;
710 710 }
711 711
712 712 .rc-user { // gravatar + user wrapper
713 713 float: left;
714 714 position: relative;
715 715 min-width: 100px;
716 716 max-width: 200px;
717 717 min-height: (@gravatar-size + @border-thickness * 2); // account for border
718 718 display: block;
719 719 padding: 0 0 0 (@gravatar-size + @basefontsize/2 + @border-thickness * 2);
720 720
721 721
722 722 .gravatar {
723 723 display: block;
724 724 position: absolute;
725 725 top: 0;
726 726 left: 0;
727 727 min-width: @gravatar-size;
728 728 min-height: @gravatar-size;
729 729 margin: 0;
730 730 }
731 731
732 732 .user {
733 733 display: block;
734 734 max-width: 175px;
735 735 padding-top: 2px;
736 736 overflow: hidden;
737 737 text-overflow: ellipsis;
738 738 }
739 739 }
740 740
741 741 .gist-gravatar,
742 742 .journal_container {
743 743 .gravatar-large {
744 744 margin: 0 .5em -10px 0;
745 745 }
746 746 }
747 747
748 748
749 749 // ADMIN SETTINGS
750 750
751 751 // Tag Patterns
752 752 .tag_patterns {
753 753 .tag_input {
754 754 margin-bottom: @padding;
755 755 }
756 756 }
757 757
758 758 .locked_input {
759 759 position: relative;
760 760
761 761 input {
762 762 display: inline;
763 763 margin-top: 3px;
764 764 }
765 765
766 766 br {
767 767 display: none;
768 768 }
769 769
770 770 .error-message {
771 771 float: left;
772 772 width: 100%;
773 773 }
774 774
775 775 .lock_input_button {
776 776 display: inline;
777 777 }
778 778
779 779 .help-block {
780 780 clear: both;
781 781 }
782 782 }
783 783
784 784 // Notifications
785 785
786 786 .notifications_buttons {
787 787 margin: 0 0 @space 0;
788 788 padding: 0;
789 789
790 790 .btn {
791 791 display: inline-block;
792 792 }
793 793 }
794 794
795 795 .notification-list {
796 796
797 797 div {
798 798 display: inline-block;
799 799 vertical-align: middle;
800 800 }
801 801
802 802 .container {
803 803 display: block;
804 804 margin: 0 0 @padding 0;
805 805 }
806 806
807 807 .delete-notifications {
808 808 margin-left: @padding;
809 809 text-align: right;
810 810 cursor: pointer;
811 811 }
812 812
813 813 .read-notifications {
814 814 margin-left: @padding/2;
815 815 text-align: right;
816 816 width: 35px;
817 817 cursor: pointer;
818 818 }
819 819
820 820 .icon-minus-sign {
821 821 color: @alert2;
822 822 }
823 823
824 824 .icon-ok-sign {
825 825 color: @alert1;
826 826 }
827 827 }
828 828
829 829 .user_settings {
830 830 float: left;
831 831 clear: both;
832 832 display: block;
833 833 width: 100%;
834 834
835 835 .gravatar_box {
836 836 margin-bottom: @padding;
837 837
838 838 &:after {
839 839 content: " ";
840 840 clear: both;
841 841 width: 100%;
842 842 }
843 843 }
844 844
845 845 .fields .field {
846 846 clear: both;
847 847 }
848 848 }
849 849
850 850 .advanced_settings {
851 851 margin-bottom: @space;
852 852
853 853 .help-block {
854 854 margin-left: 0;
855 855 }
856 856
857 857 button + .help-block {
858 858 margin-top: @padding;
859 859 }
860 860 }
861 861
862 862 // admin settings radio buttons and labels
863 863 .label-2 {
864 864 float: left;
865 865 width: @label2-width;
866 866
867 867 label {
868 868 color: @grey1;
869 869 }
870 870 }
871 871 .checkboxes {
872 872 float: left;
873 873 width: @checkboxes-width;
874 874 margin-bottom: @padding;
875 875
876 876 .checkbox {
877 877 width: 100%;
878 878
879 879 label {
880 880 margin: 0;
881 881 padding: 0;
882 882 }
883 883 }
884 884
885 885 .checkbox + .checkbox {
886 886 display: inline-block;
887 887 }
888 888
889 889 label {
890 890 margin-right: 1em;
891 891 }
892 892 }
893 893
894 894 // CHANGELOG
895 895 .container_header {
896 896 float: left;
897 897 display: block;
898 898 width: 100%;
899 899 margin: @padding 0 @padding;
900 900
901 901 #filter_changelog {
902 902 float: left;
903 903 margin-right: @padding;
904 904 }
905 905
906 906 .breadcrumbs_light {
907 907 display: inline-block;
908 908 }
909 909 }
910 910
911 911 .info_box {
912 912 float: right;
913 913 }
914 914
915 915
916 916 #graph_nodes {
917 917 padding-top: 43px;
918 918 }
919 919
920 920 #graph_content{
921 921
922 922 // adjust for table headers so that graph renders properly
923 923 // #graph_nodes padding - table cell padding
924 924 padding-top: (@space - (@basefontsize * 2.4));
925 925
926 926 &.graph_full_width {
927 927 width: 100%;
928 928 max-width: 100%;
929 929 }
930 930 }
931 931
932 932 #graph {
933 933 .flag_status {
934 934 margin: 0;
935 935 }
936 936
937 937 .pagination-left {
938 938 float: left;
939 939 clear: both;
940 940 }
941 941
942 942 .log-container {
943 943 max-width: 345px;
944 944
945 945 .message{
946 946 max-width: 340px;
947 947 }
948 948 }
949 949
950 950 .graph-col-wrapper {
951 951 padding-left: 110px;
952 952
953 953 #graph_nodes {
954 954 width: 100px;
955 955 margin-left: -110px;
956 956 float: left;
957 957 clear: left;
958 958 }
959 959 }
960
961 .load-more-commits {
962 text-align: center;
963 }
964 .load-more-commits:hover {
965 background-color: @grey7;
966 }
967 .load-more-commits {
968 a {
969 display: block;
970 }
971 }
960 972 }
961 973
962 974 #filter_changelog {
963 975 float: left;
964 976 }
965 977
966 978
967 979 //--- THEME ------------------//
968 980
969 981 #logo {
970 982 float: left;
971 983 margin: 9px 0 0 0;
972 984
973 985 .header {
974 986 background-color: transparent;
975 987 }
976 988
977 989 a {
978 990 display: inline-block;
979 991 }
980 992
981 993 img {
982 994 height:30px;
983 995 }
984 996 }
985 997
986 998 .logo-wrapper {
987 999 float:left;
988 1000 }
989 1001
990 1002 .branding{
991 1003 float: left;
992 1004 padding: 9px 2px;
993 1005 line-height: 1em;
994 1006 font-size: @navigation-fontsize;
995 1007 }
996 1008
997 1009 img {
998 1010 border: none;
999 1011 outline: none;
1000 1012 }
1001 1013 user-profile-header
1002 1014 label {
1003 1015
1004 1016 input[type="checkbox"] {
1005 1017 margin-right: 1em;
1006 1018 }
1007 1019 input[type="radio"] {
1008 1020 margin-right: 1em;
1009 1021 }
1010 1022 }
1011 1023
1012 1024 .flag_status {
1013 1025 margin: 2px 8px 6px 2px;
1014 1026 &.under_review {
1015 1027 .circle(5px, @alert3);
1016 1028 }
1017 1029 &.approved {
1018 1030 .circle(5px, @alert1);
1019 1031 }
1020 1032 &.rejected,
1021 1033 &.forced_closed{
1022 1034 .circle(5px, @alert2);
1023 1035 }
1024 1036 &.not_reviewed {
1025 1037 .circle(5px, @grey5);
1026 1038 }
1027 1039 }
1028 1040
1029 1041 .flag_status_comment_box {
1030 1042 margin: 5px 6px 0px 2px;
1031 1043 }
1032 1044 .test_pattern_preview {
1033 1045 margin: @space 0;
1034 1046
1035 1047 p {
1036 1048 margin-bottom: 0;
1037 1049 border-bottom: @border-thickness solid @border-default-color;
1038 1050 color: @grey3;
1039 1051 }
1040 1052
1041 1053 .btn {
1042 1054 margin-bottom: @padding;
1043 1055 }
1044 1056 }
1045 1057 #test_pattern_result {
1046 1058 display: none;
1047 1059 &:extend(pre);
1048 1060 padding: .9em;
1049 1061 color: @grey3;
1050 1062 background-color: @grey7;
1051 1063 border-right: @border-thickness solid @border-default-color;
1052 1064 border-bottom: @border-thickness solid @border-default-color;
1053 1065 border-left: @border-thickness solid @border-default-color;
1054 1066 }
1055 1067
1056 1068 #repo_vcs_settings {
1057 1069 #inherit_overlay_vcs_default {
1058 1070 display: none;
1059 1071 }
1060 1072 #inherit_overlay_vcs_custom {
1061 1073 display: custom;
1062 1074 }
1063 1075 &.inherited {
1064 1076 #inherit_overlay_vcs_default {
1065 1077 display: block;
1066 1078 }
1067 1079 #inherit_overlay_vcs_custom {
1068 1080 display: none;
1069 1081 }
1070 1082 }
1071 1083 }
1072 1084
1073 1085 .issue-tracker-link {
1074 1086 color: @rcblue;
1075 1087 }
1076 1088
1077 1089 // Issue Tracker Table Show/Hide
1078 1090 #repo_issue_tracker {
1079 1091 #inherit_overlay {
1080 1092 display: none;
1081 1093 }
1082 1094 #custom_overlay {
1083 1095 display: custom;
1084 1096 }
1085 1097 &.inherited {
1086 1098 #inherit_overlay {
1087 1099 display: block;
1088 1100 }
1089 1101 #custom_overlay {
1090 1102 display: none;
1091 1103 }
1092 1104 }
1093 1105 }
1094 1106 table.issuetracker {
1095 1107 &.readonly {
1096 1108 tr, td {
1097 1109 color: @grey3;
1098 1110 }
1099 1111 }
1100 1112 .edit {
1101 1113 display: none;
1102 1114 }
1103 1115 .editopen {
1104 1116 .edit {
1105 1117 display: inline;
1106 1118 }
1107 1119 .entry {
1108 1120 display: none;
1109 1121 }
1110 1122 }
1111 1123 tr td.td-action {
1112 1124 min-width: 117px;
1113 1125 }
1114 1126 td input {
1115 1127 max-width: none;
1116 1128 min-width: 30px;
1117 1129 width: 80%;
1118 1130 }
1119 1131 .issuetracker_pref input {
1120 1132 width: 40%;
1121 1133 }
1122 1134 input.edit_issuetracker_update {
1123 1135 margin-right: 0;
1124 1136 width: auto;
1125 1137 }
1126 1138 }
1127 1139
1128 1140 table.integrations {
1129 1141 .td-icon {
1130 1142 width: 20px;
1131 1143 .integration-icon {
1132 1144 height: 20px;
1133 1145 width: 20px;
1134 1146 }
1135 1147 }
1136 1148 }
1137 1149
1138 1150 .integrations {
1139 1151 a.integration-box {
1140 1152 color: @text-color;
1141 1153 &:hover {
1142 1154 .panel {
1143 1155 background: #fbfbfb;
1144 1156 }
1145 1157 }
1146 1158 .integration-icon {
1147 1159 width: 30px;
1148 1160 height: 30px;
1149 1161 margin-right: 20px;
1150 1162 float: left;
1151 1163 }
1152 1164
1153 1165 .panel-body {
1154 1166 padding: 10px;
1155 1167 }
1156 1168 .panel {
1157 1169 margin-bottom: 10px;
1158 1170 }
1159 1171 h2 {
1160 1172 display: inline-block;
1161 1173 margin: 0;
1162 1174 min-width: 140px;
1163 1175 }
1164 1176 }
1165 1177 }
1166 1178
1167 1179 //Permissions Settings
1168 1180 #add_perm {
1169 1181 margin: 0 0 @padding;
1170 1182 cursor: pointer;
1171 1183 }
1172 1184
1173 1185 .perm_ac {
1174 1186 input {
1175 1187 width: 95%;
1176 1188 }
1177 1189 }
1178 1190
1179 1191 .autocomplete-suggestions {
1180 1192 width: auto !important; // overrides autocomplete.js
1181 1193 margin: 0;
1182 1194 border: @border-thickness solid @rcblue;
1183 1195 border-radius: @border-radius;
1184 1196 color: @rcblue;
1185 1197 background-color: white;
1186 1198 }
1187 1199 .autocomplete-selected {
1188 1200 background: #F0F0F0;
1189 1201 }
1190 1202 .ac-container-wrap {
1191 1203 margin: 0;
1192 1204 padding: 8px;
1193 1205 border-bottom: @border-thickness solid @rclightblue;
1194 1206 list-style-type: none;
1195 1207 cursor: pointer;
1196 1208
1197 1209 &:hover {
1198 1210 background-color: @rclightblue;
1199 1211 }
1200 1212
1201 1213 img {
1202 1214 height: @gravatar-size;
1203 1215 width: @gravatar-size;
1204 1216 margin-right: 1em;
1205 1217 }
1206 1218
1207 1219 strong {
1208 1220 font-weight: normal;
1209 1221 }
1210 1222 }
1211 1223
1212 1224 // Settings Dropdown
1213 1225 .user-menu .container {
1214 1226 padding: 0 4px;
1215 1227 margin: 0;
1216 1228 }
1217 1229
1218 1230 .user-menu .gravatar {
1219 1231 cursor: pointer;
1220 1232 }
1221 1233
1222 1234 .codeblock {
1223 1235 margin-bottom: @padding;
1224 1236 clear: both;
1225 1237
1226 1238 .stats{
1227 1239 overflow: hidden;
1228 1240 }
1229 1241
1230 1242 .message{
1231 1243 textarea{
1232 1244 margin: 0;
1233 1245 }
1234 1246 }
1235 1247
1236 1248 .code-header {
1237 1249 .stats {
1238 1250 line-height: 2em;
1239 1251
1240 1252 .revision_id {
1241 1253 margin-left: 0;
1242 1254 }
1243 1255 .buttons {
1244 1256 padding-right: 0;
1245 1257 }
1246 1258 }
1247 1259
1248 1260 .item{
1249 1261 margin-right: 0.5em;
1250 1262 }
1251 1263 }
1252 1264
1253 1265 #editor_container{
1254 1266 position: relative;
1255 1267 margin: @padding;
1256 1268 }
1257 1269 }
1258 1270
1259 1271 #file_history_container {
1260 1272 display: none;
1261 1273 }
1262 1274
1263 1275 .file-history-inner {
1264 1276 margin-bottom: 10px;
1265 1277 }
1266 1278
1267 1279 // Pull Requests
1268 1280 .summary-details {
1269 1281 width: 72%;
1270 1282 }
1271 1283 .pr-summary {
1272 1284 border-bottom: @border-thickness solid @grey5;
1273 1285 margin-bottom: @space;
1274 1286 }
1275 1287 .reviewers-title {
1276 1288 width: 25%;
1277 1289 min-width: 200px;
1278 1290 }
1279 1291 .reviewers {
1280 1292 width: 25%;
1281 1293 min-width: 200px;
1282 1294 }
1283 1295 .reviewers ul li {
1284 1296 position: relative;
1285 1297 width: 100%;
1286 1298 margin-bottom: 8px;
1287 1299 }
1288 1300 .reviewers_member {
1289 1301 width: 100%;
1290 1302 overflow: auto;
1291 1303 }
1292 1304 .reviewer_reason {
1293 1305 padding-left: 20px;
1294 1306 }
1295 1307 .reviewer_status {
1296 1308 display: inline-block;
1297 1309 vertical-align: top;
1298 1310 width: 7%;
1299 1311 min-width: 20px;
1300 1312 height: 1.2em;
1301 1313 margin-top: 3px;
1302 1314 line-height: 1em;
1303 1315 }
1304 1316
1305 1317 .reviewer_name {
1306 1318 display: inline-block;
1307 1319 max-width: 83%;
1308 1320 padding-right: 20px;
1309 1321 vertical-align: middle;
1310 1322 line-height: 1;
1311 1323
1312 1324 .rc-user {
1313 1325 min-width: 0;
1314 1326 margin: -2px 1em 0 0;
1315 1327 }
1316 1328
1317 1329 .reviewer {
1318 1330 float: left;
1319 1331 }
1320 1332
1321 1333 &.to-delete {
1322 1334 .user,
1323 1335 .reviewer {
1324 1336 text-decoration: line-through;
1325 1337 }
1326 1338 }
1327 1339 }
1328 1340
1329 1341 .reviewer_member_remove {
1330 1342 position: absolute;
1331 1343 right: 0;
1332 1344 top: 0;
1333 1345 width: 16px;
1334 1346 margin-bottom: 10px;
1335 1347 padding: 0;
1336 1348 color: black;
1337 1349 }
1338 1350 .reviewer_member_status {
1339 1351 margin-top: 5px;
1340 1352 }
1341 1353 .pr-summary #summary{
1342 1354 width: 100%;
1343 1355 }
1344 1356 .pr-summary .action_button:hover {
1345 1357 border: 0;
1346 1358 cursor: pointer;
1347 1359 }
1348 1360 .pr-details-title {
1349 1361 padding-bottom: 8px;
1350 1362 border-bottom: @border-thickness solid @grey5;
1351 1363
1352 1364 .action_button.disabled {
1353 1365 color: @grey4;
1354 1366 cursor: inherit;
1355 1367 }
1356 1368 .action_button {
1357 1369 color: @rcblue;
1358 1370 }
1359 1371 }
1360 1372 .pr-details-content {
1361 1373 margin-top: @textmargin;
1362 1374 margin-bottom: @textmargin;
1363 1375 }
1364 1376 .pr-description {
1365 1377 white-space:pre-wrap;
1366 1378 }
1367 1379 .group_members {
1368 1380 margin-top: 0;
1369 1381 padding: 0;
1370 1382 list-style: outside none none;
1371 1383
1372 1384 img {
1373 1385 height: @gravatar-size;
1374 1386 width: @gravatar-size;
1375 1387 margin-right: .5em;
1376 1388 margin-left: 3px;
1377 1389 }
1378 1390
1379 1391 .to-delete {
1380 1392 .user {
1381 1393 text-decoration: line-through;
1382 1394 }
1383 1395 }
1384 1396 }
1385 1397
1386 1398 .compare_view_commits_title {
1387 1399 .disabled {
1388 1400 cursor: inherit;
1389 1401 &:hover{
1390 1402 background-color: inherit;
1391 1403 color: inherit;
1392 1404 }
1393 1405 }
1394 1406 }
1395 1407
1396 1408 .subtitle-compare {
1397 1409 margin: -15px 0px 0px 0px;
1398 1410 }
1399 1411
1400 1412 .comments-summary-td {
1401 1413 border-top: 1px dashed @grey5;
1402 1414 }
1403 1415
1404 1416 // new entry in group_members
1405 1417 .td-author-new-entry {
1406 1418 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1407 1419 }
1408 1420
1409 1421 .usergroup_member_remove {
1410 1422 width: 16px;
1411 1423 margin-bottom: 10px;
1412 1424 padding: 0;
1413 1425 color: black !important;
1414 1426 cursor: pointer;
1415 1427 }
1416 1428
1417 1429 .reviewer_ac .ac-input {
1418 1430 width: 92%;
1419 1431 margin-bottom: 1em;
1420 1432 }
1421 1433
1422 1434 .compare_view_commits tr{
1423 1435 height: 20px;
1424 1436 }
1425 1437 .compare_view_commits td {
1426 1438 vertical-align: top;
1427 1439 padding-top: 10px;
1428 1440 }
1429 1441 .compare_view_commits .author {
1430 1442 margin-left: 5px;
1431 1443 }
1432 1444
1433 1445 .compare_view_commits {
1434 1446 .color-a {
1435 1447 color: @alert1;
1436 1448 }
1437 1449
1438 1450 .color-c {
1439 1451 color: @color3;
1440 1452 }
1441 1453
1442 1454 .color-r {
1443 1455 color: @color5;
1444 1456 }
1445 1457
1446 1458 .color-a-bg {
1447 1459 background-color: @alert1;
1448 1460 }
1449 1461
1450 1462 .color-c-bg {
1451 1463 background-color: @alert3;
1452 1464 }
1453 1465
1454 1466 .color-r-bg {
1455 1467 background-color: @alert2;
1456 1468 }
1457 1469
1458 1470 .color-a-border {
1459 1471 border: 1px solid @alert1;
1460 1472 }
1461 1473
1462 1474 .color-c-border {
1463 1475 border: 1px solid @alert3;
1464 1476 }
1465 1477
1466 1478 .color-r-border {
1467 1479 border: 1px solid @alert2;
1468 1480 }
1469 1481
1470 1482 .commit-change-indicator {
1471 1483 width: 15px;
1472 1484 height: 15px;
1473 1485 position: relative;
1474 1486 left: 15px;
1475 1487 }
1476 1488
1477 1489 .commit-change-content {
1478 1490 text-align: center;
1479 1491 vertical-align: middle;
1480 1492 line-height: 15px;
1481 1493 }
1482 1494 }
1483 1495
1484 1496 .compare_view_files {
1485 1497 width: 100%;
1486 1498
1487 1499 td {
1488 1500 vertical-align: middle;
1489 1501 }
1490 1502 }
1491 1503
1492 1504 .compare_view_filepath {
1493 1505 color: @grey1;
1494 1506 }
1495 1507
1496 1508 .show_more {
1497 1509 display: inline-block;
1498 1510 position: relative;
1499 1511 vertical-align: middle;
1500 1512 width: 4px;
1501 1513 height: @basefontsize;
1502 1514
1503 1515 &:after {
1504 1516 content: "\00A0\25BE";
1505 1517 display: inline-block;
1506 1518 width:10px;
1507 1519 line-height: 5px;
1508 1520 font-size: 12px;
1509 1521 cursor: pointer;
1510 1522 }
1511 1523 }
1512 1524
1513 1525 .journal_more .show_more {
1514 1526 display: inline;
1515 1527
1516 1528 &:after {
1517 1529 content: none;
1518 1530 }
1519 1531 }
1520 1532
1521 1533 .open .show_more:after,
1522 1534 .select2-dropdown-open .show_more:after {
1523 1535 .rotate(180deg);
1524 1536 margin-left: 4px;
1525 1537 }
1526 1538
1527 1539
1528 1540 .compare_view_commits .collapse_commit:after {
1529 1541 cursor: pointer;
1530 1542 content: "\00A0\25B4";
1531 1543 margin-left: -3px;
1532 1544 font-size: 17px;
1533 1545 color: @grey4;
1534 1546 }
1535 1547
1536 1548 .diff_links {
1537 1549 margin-left: 8px;
1538 1550 }
1539 1551
1540 1552 div.ancestor {
1541 1553 margin: -30px 0px;
1542 1554 }
1543 1555
1544 1556 .cs_icon_td input[type="checkbox"] {
1545 1557 display: none;
1546 1558 }
1547 1559
1548 1560 .cs_icon_td .expand_file_icon:after {
1549 1561 cursor: pointer;
1550 1562 content: "\00A0\25B6";
1551 1563 font-size: 12px;
1552 1564 color: @grey4;
1553 1565 }
1554 1566
1555 1567 .cs_icon_td .collapse_file_icon:after {
1556 1568 cursor: pointer;
1557 1569 content: "\00A0\25BC";
1558 1570 font-size: 12px;
1559 1571 color: @grey4;
1560 1572 }
1561 1573
1562 1574 /*new binary
1563 1575 NEW_FILENODE = 1
1564 1576 DEL_FILENODE = 2
1565 1577 MOD_FILENODE = 3
1566 1578 RENAMED_FILENODE = 4
1567 1579 COPIED_FILENODE = 5
1568 1580 CHMOD_FILENODE = 6
1569 1581 BIN_FILENODE = 7
1570 1582 */
1571 1583 .cs_files_expand {
1572 1584 font-size: @basefontsize + 5px;
1573 1585 line-height: 1.8em;
1574 1586 float: right;
1575 1587 }
1576 1588
1577 1589 .cs_files_expand span{
1578 1590 color: @rcblue;
1579 1591 cursor: pointer;
1580 1592 }
1581 1593 .cs_files {
1582 1594 clear: both;
1583 1595 padding-bottom: @padding;
1584 1596
1585 1597 .cur_cs {
1586 1598 margin: 10px 2px;
1587 1599 font-weight: bold;
1588 1600 }
1589 1601
1590 1602 .node {
1591 1603 float: left;
1592 1604 }
1593 1605
1594 1606 .changes {
1595 1607 float: right;
1596 1608 color: white;
1597 1609 font-size: @basefontsize - 4px;
1598 1610 margin-top: 4px;
1599 1611 opacity: 0.6;
1600 1612 filter: Alpha(opacity=60); /* IE8 and earlier */
1601 1613
1602 1614 .added {
1603 1615 background-color: @alert1;
1604 1616 float: left;
1605 1617 text-align: center;
1606 1618 }
1607 1619
1608 1620 .deleted {
1609 1621 background-color: @alert2;
1610 1622 float: left;
1611 1623 text-align: center;
1612 1624 }
1613 1625
1614 1626 .bin {
1615 1627 background-color: @alert1;
1616 1628 text-align: center;
1617 1629 }
1618 1630
1619 1631 /*new binary*/
1620 1632 .bin.bin1 {
1621 1633 background-color: @alert1;
1622 1634 text-align: center;
1623 1635 }
1624 1636
1625 1637 /*deleted binary*/
1626 1638 .bin.bin2 {
1627 1639 background-color: @alert2;
1628 1640 text-align: center;
1629 1641 }
1630 1642
1631 1643 /*mod binary*/
1632 1644 .bin.bin3 {
1633 1645 background-color: @grey2;
1634 1646 text-align: center;
1635 1647 }
1636 1648
1637 1649 /*rename file*/
1638 1650 .bin.bin4 {
1639 1651 background-color: @alert4;
1640 1652 text-align: center;
1641 1653 }
1642 1654
1643 1655 /*copied file*/
1644 1656 .bin.bin5 {
1645 1657 background-color: @alert4;
1646 1658 text-align: center;
1647 1659 }
1648 1660
1649 1661 /*chmod file*/
1650 1662 .bin.bin6 {
1651 1663 background-color: @grey2;
1652 1664 text-align: center;
1653 1665 }
1654 1666 }
1655 1667 }
1656 1668
1657 1669 .cs_files .cs_added, .cs_files .cs_A,
1658 1670 .cs_files .cs_added, .cs_files .cs_M,
1659 1671 .cs_files .cs_added, .cs_files .cs_D {
1660 1672 height: 16px;
1661 1673 padding-right: 10px;
1662 1674 margin-top: 7px;
1663 1675 text-align: left;
1664 1676 }
1665 1677
1666 1678 .cs_icon_td {
1667 1679 min-width: 16px;
1668 1680 width: 16px;
1669 1681 }
1670 1682
1671 1683 .pull-request-merge {
1672 1684 border: 1px solid @grey5;
1673 1685 padding: 10px 0px 20px;
1674 1686 margin-top: 10px;
1675 1687 margin-bottom: 20px;
1676 1688 }
1677 1689
1678 1690 .pull-request-merge ul {
1679 1691 padding: 0px 0px;
1680 1692 }
1681 1693
1682 1694 .pull-request-merge li:before{
1683 1695 content:none;
1684 1696 }
1685 1697
1686 1698 .pull-request-merge .pull-request-wrap {
1687 1699 height: auto;
1688 1700 padding: 0px 0px;
1689 1701 text-align: right;
1690 1702 }
1691 1703
1692 1704 .pull-request-merge span {
1693 1705 margin-right: 5px;
1694 1706 }
1695 1707
1696 1708 .pull-request-merge-actions {
1697 1709 height: 30px;
1698 1710 padding: 0px 0px;
1699 1711 }
1700 1712
1701 1713 .merge-status {
1702 1714 margin-right: 5px;
1703 1715 }
1704 1716
1705 1717 .merge-message {
1706 1718 font-size: 1.2em
1707 1719 }
1708 1720
1709 1721 .merge-message.success i,
1710 1722 .merge-icon.success i {
1711 1723 color:@alert1;
1712 1724 }
1713 1725
1714 1726 .merge-message.warning i,
1715 1727 .merge-icon.warning i {
1716 1728 color: @alert3;
1717 1729 }
1718 1730
1719 1731 .merge-message.error i,
1720 1732 .merge-icon.error i {
1721 1733 color:@alert2;
1722 1734 }
1723 1735
1724 1736 .pr-versions {
1725 1737 font-size: 1.1em;
1726 1738
1727 1739 table {
1728 1740 padding: 0px 5px;
1729 1741 }
1730 1742
1731 1743 td {
1732 1744 line-height: 15px;
1733 1745 }
1734 1746
1735 1747 .flag_status {
1736 1748 margin: 0;
1737 1749 }
1738 1750
1739 1751 .compare-radio-button {
1740 1752 position: relative;
1741 1753 top: -3px;
1742 1754 }
1743 1755 }
1744 1756
1745 1757
1746 1758 #close_pull_request {
1747 1759 margin-right: 0px;
1748 1760 }
1749 1761
1750 1762 .empty_data {
1751 1763 color: @grey4;
1752 1764 }
1753 1765
1754 1766 #changeset_compare_view_content {
1755 1767 margin-bottom: @space;
1756 1768 clear: both;
1757 1769 width: 100%;
1758 1770 box-sizing: border-box;
1759 1771 .border-radius(@border-radius);
1760 1772
1761 1773 .help-block {
1762 1774 margin: @padding 0;
1763 1775 color: @text-color;
1764 1776 }
1765 1777
1766 1778 .empty_data {
1767 1779 margin: @padding 0;
1768 1780 }
1769 1781
1770 1782 .alert {
1771 1783 margin-bottom: @space;
1772 1784 }
1773 1785 }
1774 1786
1775 1787 .table_disp {
1776 1788 .status {
1777 1789 width: auto;
1778 1790
1779 1791 .flag_status {
1780 1792 float: left;
1781 1793 }
1782 1794 }
1783 1795 }
1784 1796
1785 1797 .status_box_menu {
1786 1798 margin: 0;
1787 1799 }
1788 1800
1789 1801 .notification-table{
1790 1802 margin-bottom: @space;
1791 1803 display: table;
1792 1804 width: 100%;
1793 1805
1794 1806 .container{
1795 1807 display: table-row;
1796 1808
1797 1809 .notification-header{
1798 1810 border-bottom: @border-thickness solid @border-default-color;
1799 1811 }
1800 1812
1801 1813 .notification-subject{
1802 1814 display: table-cell;
1803 1815 }
1804 1816 }
1805 1817 }
1806 1818
1807 1819 // Notifications
1808 1820 .notification-header{
1809 1821 display: table;
1810 1822 width: 100%;
1811 1823 padding: floor(@basefontsize/2) 0;
1812 1824 line-height: 1em;
1813 1825
1814 1826 .desc, .delete-notifications, .read-notifications{
1815 1827 display: table-cell;
1816 1828 text-align: left;
1817 1829 }
1818 1830
1819 1831 .desc{
1820 1832 width: 1163px;
1821 1833 }
1822 1834
1823 1835 .delete-notifications, .read-notifications{
1824 1836 width: 35px;
1825 1837 min-width: 35px; //fixes when only one button is displayed
1826 1838 }
1827 1839 }
1828 1840
1829 1841 .notification-body {
1830 1842 .markdown-block,
1831 1843 .rst-block {
1832 1844 padding: @padding 0;
1833 1845 }
1834 1846
1835 1847 .notification-subject {
1836 1848 padding: @textmargin 0;
1837 1849 border-bottom: @border-thickness solid @border-default-color;
1838 1850 }
1839 1851 }
1840 1852
1841 1853
1842 1854 .notifications_buttons{
1843 1855 float: right;
1844 1856 }
1845 1857
1846 1858 #notification-status{
1847 1859 display: inline;
1848 1860 }
1849 1861
1850 1862 // Repositories
1851 1863
1852 1864 #summary.fields{
1853 1865 display: table;
1854 1866
1855 1867 .field{
1856 1868 display: table-row;
1857 1869
1858 1870 .label-summary{
1859 1871 display: table-cell;
1860 1872 min-width: @label-summary-minwidth;
1861 1873 padding-top: @padding/2;
1862 1874 padding-bottom: @padding/2;
1863 1875 padding-right: @padding/2;
1864 1876 }
1865 1877
1866 1878 .input{
1867 1879 display: table-cell;
1868 1880 padding: @padding/2;
1869 1881
1870 1882 input{
1871 1883 min-width: 29em;
1872 1884 padding: @padding/4;
1873 1885 }
1874 1886 }
1875 1887 .statistics, .downloads{
1876 1888 .disabled{
1877 1889 color: @grey4;
1878 1890 }
1879 1891 }
1880 1892 }
1881 1893 }
1882 1894
1883 1895 #summary{
1884 1896 width: 70%;
1885 1897 }
1886 1898
1887 1899
1888 1900 // Journal
1889 1901 .journal.title {
1890 1902 h5 {
1891 1903 float: left;
1892 1904 margin: 0;
1893 1905 width: 70%;
1894 1906 }
1895 1907
1896 1908 ul {
1897 1909 float: right;
1898 1910 display: inline-block;
1899 1911 margin: 0;
1900 1912 width: 30%;
1901 1913 text-align: right;
1902 1914
1903 1915 li {
1904 1916 display: inline;
1905 1917 font-size: @journal-fontsize;
1906 1918 line-height: 1em;
1907 1919
1908 1920 &:before { content: none; }
1909 1921 }
1910 1922 }
1911 1923 }
1912 1924
1913 1925 .filterexample {
1914 1926 position: absolute;
1915 1927 top: 95px;
1916 1928 left: @contentpadding;
1917 1929 color: @rcblue;
1918 1930 font-size: 11px;
1919 1931 font-family: @text-regular;
1920 1932 cursor: help;
1921 1933
1922 1934 &:hover {
1923 1935 color: @rcdarkblue;
1924 1936 }
1925 1937
1926 1938 @media (max-width:768px) {
1927 1939 position: relative;
1928 1940 top: auto;
1929 1941 left: auto;
1930 1942 display: block;
1931 1943 }
1932 1944 }
1933 1945
1934 1946
1935 1947 #journal{
1936 1948 margin-bottom: @space;
1937 1949
1938 1950 .journal_day{
1939 1951 margin-bottom: @textmargin/2;
1940 1952 padding-bottom: @textmargin/2;
1941 1953 font-size: @journal-fontsize;
1942 1954 border-bottom: @border-thickness solid @border-default-color;
1943 1955 }
1944 1956
1945 1957 .journal_container{
1946 1958 margin-bottom: @space;
1947 1959
1948 1960 .journal_user{
1949 1961 display: inline-block;
1950 1962 }
1951 1963 .journal_action_container{
1952 1964 display: block;
1953 1965 margin-top: @textmargin;
1954 1966
1955 1967 div{
1956 1968 display: inline;
1957 1969 }
1958 1970
1959 1971 div.journal_action_params{
1960 1972 display: block;
1961 1973 }
1962 1974
1963 1975 div.journal_repo:after{
1964 1976 content: "\A";
1965 1977 white-space: pre;
1966 1978 }
1967 1979
1968 1980 div.date{
1969 1981 display: block;
1970 1982 margin-bottom: @textmargin;
1971 1983 }
1972 1984 }
1973 1985 }
1974 1986 }
1975 1987
1976 1988 // Files
1977 1989 .edit-file-title {
1978 1990 border-bottom: @border-thickness solid @border-default-color;
1979 1991
1980 1992 .breadcrumbs {
1981 1993 margin-bottom: 0;
1982 1994 }
1983 1995 }
1984 1996
1985 1997 .edit-file-fieldset {
1986 1998 margin-top: @sidebarpadding;
1987 1999
1988 2000 .fieldset {
1989 2001 .left-label {
1990 2002 width: 13%;
1991 2003 }
1992 2004 .right-content {
1993 2005 width: 87%;
1994 2006 max-width: 100%;
1995 2007 }
1996 2008 .filename-label {
1997 2009 margin-top: 13px;
1998 2010 }
1999 2011 .commit-message-label {
2000 2012 margin-top: 4px;
2001 2013 }
2002 2014 .file-upload-input {
2003 2015 input {
2004 2016 display: none;
2005 2017 }
2006 2018 }
2007 2019 p {
2008 2020 margin-top: 5px;
2009 2021 }
2010 2022
2011 2023 }
2012 2024 .custom-path-link {
2013 2025 margin-left: 5px;
2014 2026 }
2015 2027 #commit {
2016 2028 resize: vertical;
2017 2029 }
2018 2030 }
2019 2031
2020 2032 .delete-file-preview {
2021 2033 max-height: 250px;
2022 2034 }
2023 2035
2024 2036 .new-file,
2025 2037 #filter_activate,
2026 2038 #filter_deactivate {
2027 2039 float: left;
2028 2040 margin: 0 0 0 15px;
2029 2041 }
2030 2042
2031 2043 h3.files_location{
2032 2044 line-height: 2.4em;
2033 2045 }
2034 2046
2035 2047 .browser-nav {
2036 2048 display: table;
2037 2049 margin-bottom: @space;
2038 2050
2039 2051
2040 2052 .info_box {
2041 2053 display: inline-table;
2042 2054 height: 2.5em;
2043 2055
2044 2056 .browser-cur-rev, .info_box_elem {
2045 2057 display: table-cell;
2046 2058 vertical-align: middle;
2047 2059 }
2048 2060
2049 2061 .info_box_elem {
2050 2062 border-top: @border-thickness solid @rcblue;
2051 2063 border-bottom: @border-thickness solid @rcblue;
2052 2064
2053 2065 #at_rev, a {
2054 2066 padding: 0.6em 0.9em;
2055 2067 margin: 0;
2056 2068 .box-shadow(none);
2057 2069 border: 0;
2058 2070 height: 12px;
2059 2071 }
2060 2072
2061 2073 input#at_rev {
2062 2074 max-width: 50px;
2063 2075 text-align: right;
2064 2076 }
2065 2077
2066 2078 &.previous {
2067 2079 border: @border-thickness solid @rcblue;
2068 2080 .disabled {
2069 2081 color: @grey4;
2070 2082 cursor: not-allowed;
2071 2083 }
2072 2084 }
2073 2085
2074 2086 &.next {
2075 2087 border: @border-thickness solid @rcblue;
2076 2088 .disabled {
2077 2089 color: @grey4;
2078 2090 cursor: not-allowed;
2079 2091 }
2080 2092 }
2081 2093 }
2082 2094
2083 2095 .browser-cur-rev {
2084 2096
2085 2097 span{
2086 2098 margin: 0;
2087 2099 color: @rcblue;
2088 2100 height: 12px;
2089 2101 display: inline-block;
2090 2102 padding: 0.7em 1em ;
2091 2103 border: @border-thickness solid @rcblue;
2092 2104 margin-right: @padding;
2093 2105 }
2094 2106 }
2095 2107 }
2096 2108
2097 2109 .search_activate {
2098 2110 display: table-cell;
2099 2111 vertical-align: middle;
2100 2112
2101 2113 input, label{
2102 2114 margin: 0;
2103 2115 padding: 0;
2104 2116 }
2105 2117
2106 2118 input{
2107 2119 margin-left: @textmargin;
2108 2120 }
2109 2121
2110 2122 }
2111 2123 }
2112 2124
2113 2125 .browser-cur-rev{
2114 2126 margin-bottom: @textmargin;
2115 2127 }
2116 2128
2117 2129 #node_filter_box_loading{
2118 2130 .info_text;
2119 2131 }
2120 2132
2121 2133 .browser-search {
2122 2134 margin: -25px 0px 5px 0px;
2123 2135 }
2124 2136
2125 2137 .node-filter {
2126 2138 font-size: @repo-title-fontsize;
2127 2139 padding: 4px 0px 0px 0px;
2128 2140
2129 2141 .node-filter-path {
2130 2142 float: left;
2131 2143 color: @grey4;
2132 2144 }
2133 2145 .node-filter-input {
2134 2146 float: left;
2135 2147 margin: -2px 0px 0px 2px;
2136 2148 input {
2137 2149 padding: 2px;
2138 2150 border: none;
2139 2151 font-size: @repo-title-fontsize;
2140 2152 }
2141 2153 }
2142 2154 }
2143 2155
2144 2156
2145 2157 .browser-result{
2146 2158 td a{
2147 2159 margin-left: 0.5em;
2148 2160 display: inline-block;
2149 2161
2150 2162 em{
2151 2163 font-family: @text-bold;
2152 2164 }
2153 2165 }
2154 2166 }
2155 2167
2156 2168 .browser-highlight{
2157 2169 background-color: @grey5-alpha;
2158 2170 }
2159 2171
2160 2172
2161 2173 // Search
2162 2174
2163 2175 .search-form{
2164 2176 #q {
2165 2177 width: @search-form-width;
2166 2178 }
2167 2179 .fields{
2168 2180 margin: 0 0 @space;
2169 2181 }
2170 2182
2171 2183 label{
2172 2184 display: inline-block;
2173 2185 margin-right: @textmargin;
2174 2186 padding-top: 0.25em;
2175 2187 }
2176 2188
2177 2189
2178 2190 .results{
2179 2191 clear: both;
2180 2192 margin: 0 0 @padding;
2181 2193 }
2182 2194 }
2183 2195
2184 2196 div.search-feedback-items {
2185 2197 display: inline-block;
2186 2198 padding:0px 0px 0px 96px;
2187 2199 }
2188 2200
2189 2201 div.search-code-body {
2190 2202 background-color: #ffffff; padding: 5px 0 5px 10px;
2191 2203 pre {
2192 2204 .match { background-color: #faffa6;}
2193 2205 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2194 2206 }
2195 2207 }
2196 2208
2197 2209 .expand_commit.search {
2198 2210 .show_more.open {
2199 2211 height: auto;
2200 2212 max-height: none;
2201 2213 }
2202 2214 }
2203 2215
2204 2216 .search-results {
2205 2217
2206 2218 h2 {
2207 2219 margin-bottom: 0;
2208 2220 }
2209 2221 .codeblock {
2210 2222 border: none;
2211 2223 background: transparent;
2212 2224 }
2213 2225
2214 2226 .codeblock-header {
2215 2227 border: none;
2216 2228 background: transparent;
2217 2229 }
2218 2230
2219 2231 .code-body {
2220 2232 border: @border-thickness solid @border-default-color;
2221 2233 .border-radius(@border-radius);
2222 2234 }
2223 2235
2224 2236 .td-commit {
2225 2237 &:extend(pre);
2226 2238 border-bottom: @border-thickness solid @border-default-color;
2227 2239 }
2228 2240
2229 2241 .message {
2230 2242 height: auto;
2231 2243 max-width: 350px;
2232 2244 white-space: normal;
2233 2245 text-overflow: initial;
2234 2246 overflow: visible;
2235 2247
2236 2248 .match { background-color: #faffa6;}
2237 2249 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2238 2250 }
2239 2251
2240 2252 }
2241 2253
2242 2254 table.rctable td.td-search-results div {
2243 2255 max-width: 100%;
2244 2256 }
2245 2257
2246 2258 #tip-box, .tip-box{
2247 2259 padding: @menupadding/2;
2248 2260 display: block;
2249 2261 border: @border-thickness solid @border-highlight-color;
2250 2262 .border-radius(@border-radius);
2251 2263 background-color: white;
2252 2264 z-index: 99;
2253 2265 white-space: pre-wrap;
2254 2266 }
2255 2267
2256 2268 #linktt {
2257 2269 width: 79px;
2258 2270 }
2259 2271
2260 2272 #help_kb .modal-content{
2261 2273 max-width: 750px;
2262 2274 margin: 10% auto;
2263 2275
2264 2276 table{
2265 2277 td,th{
2266 2278 border-bottom: none;
2267 2279 line-height: 2.5em;
2268 2280 }
2269 2281 th{
2270 2282 padding-bottom: @textmargin/2;
2271 2283 }
2272 2284 td.keys{
2273 2285 text-align: center;
2274 2286 }
2275 2287 }
2276 2288
2277 2289 .block-left{
2278 2290 width: 45%;
2279 2291 margin-right: 5%;
2280 2292 }
2281 2293 .modal-footer{
2282 2294 clear: both;
2283 2295 }
2284 2296 .key.tag{
2285 2297 padding: 0.5em;
2286 2298 background-color: @rcblue;
2287 2299 color: white;
2288 2300 border-color: @rcblue;
2289 2301 .box-shadow(none);
2290 2302 }
2291 2303 }
2292 2304
2293 2305
2294 2306
2295 2307 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2296 2308
2297 2309 @import 'statistics-graph';
2298 2310 @import 'tables';
2299 2311 @import 'forms';
2300 2312 @import 'diff';
2301 2313 @import 'summary';
2302 2314 @import 'navigation';
2303 2315
2304 2316 //--- SHOW/HIDE SECTIONS --//
2305 2317
2306 2318 .btn-collapse {
2307 2319 float: right;
2308 2320 text-align: right;
2309 2321 font-family: @text-light;
2310 2322 font-size: @basefontsize;
2311 2323 cursor: pointer;
2312 2324 border: none;
2313 2325 color: @rcblue;
2314 2326 }
2315 2327
2316 2328 table.rctable,
2317 2329 table.dataTable {
2318 2330 .btn-collapse {
2319 2331 float: right;
2320 2332 text-align: right;
2321 2333 }
2322 2334 }
2323 2335
2324 2336
2325 2337 // TODO: johbo: Fix for IE10, this avoids that we see a border
2326 2338 // and padding around checkboxes and radio boxes. Move to the right place,
2327 2339 // or better: Remove this once we did the form refactoring.
2328 2340 input[type=checkbox],
2329 2341 input[type=radio] {
2330 2342 padding: 0;
2331 2343 border: none;
2332 2344 }
2333 2345
2334 2346 .toggle-ajax-spinner{
2335 2347 height: 16px;
2336 2348 width: 16px;
2337 2349 }
@@ -1,541 +1,542 b''
1 1 //
2 2 // Typography
3 3 // modified from Bootstrap
4 4 // --------------------------------------------------
5 5
6 6 // Base
7 7 body {
8 8 font-size: @basefontsize;
9 9 font-family: @text-light;
10 10 letter-spacing: .02em;
11 11 color: @grey2;
12 12 }
13 13
14 14 #content, label{
15 15 font-size: @basefontsize;
16 16 }
17 17
18 18 label {
19 19 color: @grey2;
20 20 }
21 21
22 22 ::selection { background: @rchighlightblue; }
23 23
24 24 // Headings
25 25 // -------------------------
26 26
27 27 h1, h2, h3, h4, h5, h6,
28 28 .h1, .h2, .h3, .h4, .h5, .h6 {
29 29 margin: 0 0 @textmargin 0;
30 30 padding: 0;
31 31 line-height: 1.8em;
32 32 color: @text-color;
33 33 a {
34 34 color: @rcblue;
35 35 }
36 36 }
37 37
38 38 h1, .h1 { font-size: 1.54em; font-family: @text-bold; }
39 39 h2, .h2 { font-size: 1.23em; font-family: @text-semibold; }
40 40 h3, .h3 { font-size: 1.23em; font-family: @text-regular; }
41 41 h4, .h4 { font-size: 1em; font-family: @text-bold; }
42 42 h5, .h5 { font-size: 1em; font-family: @text-bold-italic; }
43 43 h6, .h6 { font-size: 1em; font-family: @text-bold-italic; }
44 44
45 45 // Breadcrumbs
46 46 .breadcrumbs {
47 47 &:extend(h1);
48 48 margin: 0;
49 49 }
50 50
51 51 .breadcrumbs_light {
52 52 float:left;
53 margin: @padding 0;
53 font-size: 1.3em;
54 line-height: 38px;
54 55 }
55 56
56 57 // Body text
57 58 // -------------------------
58 59
59 60 p {
60 61 margin: 0 0 @textmargin 0;
61 62 padding: 0;
62 63 line-height: 2em;
63 64 }
64 65
65 66 .lead {
66 67 margin-bottom: @textmargin;
67 68 font-weight: 300;
68 69 line-height: 1.4;
69 70
70 71 @media (min-width: @screen-sm-min) {
71 72 font-size: (@basefontsize * 1.5);
72 73 }
73 74 }
74 75
75 76 a,
76 77 .link {
77 78 color: @rcblue;
78 79 text-decoration: none;
79 80 outline: none;
80 81 cursor: pointer;
81 82
82 83 &:focus {
83 84 outline: none;
84 85 }
85 86
86 87 &:hover {
87 88 color: @rcdarkblue;
88 89 }
89 90 }
90 91
91 92 img {
92 93 border: none;
93 94 outline: none;
94 95 }
95 96
96 97 strong {
97 98 font-family: @text-bold;
98 99 }
99 100
100 101 em {
101 102 font-family: @text-italic;
102 103 }
103 104
104 105 strong em,
105 106 em strong {
106 107 font-family: @text-bold-italic;
107 108 }
108 109
109 110 //TODO: lisa: b and i are depreciated, but we are still using them in places.
110 111 // Should probably make some decision whether to keep or lose these.
111 112 b {
112 113
113 114 }
114 115
115 116 i {
116 117 font-style: normal;
117 118 }
118 119
119 120 label {
120 121 color: @text-color;
121 122
122 123 input[type="checkbox"] {
123 124 margin-right: 1em;
124 125 }
125 126 input[type="radio"] {
126 127 margin-right: 1em;
127 128 }
128 129 }
129 130
130 131 code,
131 132 .code {
132 133 font-size: .95em;
133 134 font-family: "Lucida Console", Monaco, monospace;
134 135 color: @grey3;
135 136
136 137 a {
137 138 color: lighten(@rcblue,10%)
138 139 }
139 140 }
140 141
141 142 pre {
142 143 margin: 0;
143 144 padding: 0;
144 145 border: 0;
145 146 outline: 0;
146 147 font-size: @basefontsize*.95;
147 148 line-height: 1.4em;
148 149 font-family: "Lucida Console", Monaco, monospace;
149 150 color: @grey3;
150 151 }
151 152
152 153 // Emphasis & misc
153 154 // -------------------------
154 155
155 156 small,
156 157 .small {
157 158 font-size: 75%;
158 159 font-weight: normal;
159 160 line-height: 1em;
160 161 }
161 162
162 163 mark,
163 164 .mark {
164 165 background-color: @rclightblue;
165 166 padding: .2em;
166 167 }
167 168
168 169 // Alignment
169 170 .text-left { text-align: left; }
170 171 .text-right { text-align: right; }
171 172 .text-center { text-align: center; }
172 173 .text-justify { text-align: justify; }
173 174 .text-nowrap { white-space: nowrap; }
174 175
175 176 // Transformation
176 177 .text-lowercase { text-transform: lowercase; }
177 178 .text-uppercase { text-transform: uppercase; }
178 179 .text-capitalize { text-transform: capitalize; }
179 180
180 181 // Contextual colors
181 182 .text-muted {
182 183 color: @grey4;
183 184 }
184 185 .text-primary {
185 186 color: @rcblue;
186 187 }
187 188 .text-success {
188 189 color: @alert1;
189 190 }
190 191 .text-info {
191 192 color: @alert4;
192 193 }
193 194 .text-warning {
194 195 color: @alert3;
195 196 }
196 197 .text-danger {
197 198 color: @alert2;
198 199 }
199 200
200 201 // Contextual backgrounds
201 202 .bg-primary {
202 203 background-color: white;
203 204 }
204 205 .bg-success {
205 206 background-color: @alert1;
206 207 }
207 208 .bg-info {
208 209 background-color: @alert4;
209 210 }
210 211 .bg-warning {
211 212 background-color: @alert3;
212 213 }
213 214 .bg-danger {
214 215 background-color: @alert2;
215 216 }
216 217
217 218
218 219 // Page header
219 220 // -------------------------
220 221
221 222 .page-header {
222 223 margin: @pagepadding 0 @textmargin;
223 224 border-bottom: @border-thickness solid @grey5;
224 225 }
225 226
226 227 .title {
227 228 clear: both;
228 229 float: left;
229 230 width: 100%;
230 231 margin: @pagepadding 0 @pagepadding;
231 232
232 233 .breadcrumbs{
233 234 float: left;
234 235 clear: both;
235 236 width: 700px;
236 237 margin: 0;
237 238
238 239 .q_filter_box {
239 240 margin-right: @padding;
240 241 }
241 242 }
242 243
243 244 h1 a {
244 245 color: @rcblue;
245 246 }
246 247
247 248 input{
248 249 margin-right: @padding;
249 250 }
250 251
251 252 h5, .h5 {
252 253 color: @grey1;
253 254 margin-bottom: @space;
254 255
255 256 span {
256 257 display: inline-block;
257 258 }
258 259 }
259 260
260 261 p {
261 262 margin-bottom: 0;
262 263 }
263 264
264 265 .links {
265 266 float: right;
266 267 display: inline;
267 268 margin: 0;
268 269 padding-left: 0;
269 270 list-style: none;
270 271 text-align: right;
271 272
272 273 li:before { content: none; }
273 274 li { float: right; }
274 275 a {
275 276 display: inline-block;
276 277 margin-left: @textmargin/2;
277 278 }
278 279 }
279 280
280 281 .title-content {
281 282 float: left;
282 283 margin: 0;
283 284 padding: 0;
284 285
285 286 & + .breadcrumbs {
286 287 margin-top: @padding;
287 288 }
288 289
289 290 & + .links {
290 291 margin-top: -@button-padding;
291 292
292 293 & + .breadcrumbs {
293 294 margin-top: @padding;
294 295 }
295 296 }
296 297 }
297 298
298 299 .title-main {
299 300 font-size: @repo-title-fontsize;
300 301 }
301 302
302 303 .title-description {
303 304 margin-top: .5em;
304 305 }
305 306
306 307 .q_filter_box {
307 308 width: 200px;
308 309 }
309 310
310 311 }
311 312
312 313 #readme .title {
313 314 text-transform: none;
314 315 }
315 316
316 317 // Lists
317 318 // -------------------------
318 319
319 320 // Unordered and Ordered lists
320 321 ul,
321 322 ol {
322 323 margin-top: 0;
323 324 margin-bottom: @textmargin;
324 325 ul,
325 326 ol {
326 327 margin-bottom: 0;
327 328 }
328 329 }
329 330
330 331 li {
331 332 line-height: 2em;
332 333 }
333 334
334 335 ul li {
335 336 position: relative;
336 337 display: block;
337 338 list-style-type: none;
338 339
339 340 &:before {
340 341 content: "\2014\00A0";
341 342 position: absolute;
342 343 top: 0;
343 344 left: -1.25em;
344 345 }
345 346
346 347 p:first-child {
347 348 display:inline;
348 349 }
349 350 }
350 351
351 352 // List options
352 353
353 354 // Unstyled keeps list items block level, just removes default browser padding and list-style
354 355 .list-unstyled {
355 356 padding-left: 0;
356 357 list-style: none;
357 358 li:before { content: none; }
358 359 }
359 360
360 361 // Inline turns list items into inline-block
361 362 .list-inline {
362 363 .list-unstyled();
363 364 margin-left: -5px;
364 365
365 366 > li {
366 367 display: inline-block;
367 368 padding-left: 5px;
368 369 padding-right: 5px;
369 370 }
370 371 }
371 372
372 373 // Description Lists
373 374
374 375 dl {
375 376 margin-top: 0; // Remove browser default
376 377 margin-bottom: @textmargin;
377 378 }
378 379
379 380 dt,
380 381 dd {
381 382 line-height: 1.4em;
382 383 }
383 384
384 385 dt {
385 386 margin: @textmargin 0 0 0;
386 387 font-family: @text-bold;
387 388 }
388 389
389 390 dd {
390 391 margin-left: 0; // Undo browser default
391 392 }
392 393
393 394 // Horizontal description lists
394 395 // Defaults to being stacked without any of the below styles applied, until the
395 396 // grid breakpoint is reached (default of ~768px).
396 397 // These are used in forms as well; see style guide.
397 398 // TODO: lisa: These should really not be used in forms.
398 399
399 400 .dl-horizontal {
400 401
401 402 overflow: hidden;
402 403 margin-bottom: @space;
403 404
404 405 dt, dd {
405 406 float: left;
406 407 margin: 5px 0 5px 0;
407 408 }
408 409
409 410 dt {
410 411 clear: left;
411 412 width: @label-width - @form-vertical-margin;
412 413 }
413 414
414 415 dd {
415 416 &:extend(.clearfix all); // Clear the floated `dt` if an empty `dd` is present
416 417 margin-left: @form-vertical-margin;
417 418 max-width: @form-max-width - (@label-width - @form-vertical-margin) - @form-vertical-margin;
418 419 }
419 420
420 421 pre {
421 422 margin: 0;
422 423 }
423 424
424 425 &.settings {
425 426 dt {
426 427 text-align: left;
427 428 }
428 429 }
429 430
430 431 @media (min-width: 768px) {
431 432 dt {
432 433 float: left;
433 434 width: 180px;
434 435 clear: left;
435 436 text-align: right;
436 437 }
437 438 dd {
438 439 margin-left: 20px;
439 440 }
440 441 }
441 442 }
442 443
443 444
444 445 // Misc
445 446 // -------------------------
446 447
447 448 // Abbreviations and acronyms
448 449 abbr[title],
449 450 abbr[data-original-title] {
450 451 cursor: help;
451 452 border-bottom: @border-thickness dotted @grey4;
452 453 }
453 454 .initialism {
454 455 font-size: 90%;
455 456 text-transform: uppercase;
456 457 }
457 458
458 459 // Blockquotes
459 460 blockquote {
460 461 padding: 1em 2em;
461 462 margin: 0 0 2em;
462 463 font-size: @basefontsize;
463 464 border-left: 2px solid @grey6;
464 465
465 466 p,
466 467 ul,
467 468 ol {
468 469 &:last-child {
469 470 margin-bottom: 0;
470 471 }
471 472 }
472 473
473 474 footer,
474 475 small,
475 476 .small {
476 477 display: block;
477 478 font-size: 80%;
478 479
479 480 &:before {
480 481 content: '\2014 \00A0'; // em dash, nbsp
481 482 }
482 483 }
483 484 }
484 485
485 486 // Opposite alignment of blockquote
486 487 //
487 488 .blockquote-reverse,
488 489 blockquote.pull-right {
489 490 padding-right: 15px;
490 491 padding-left: 0;
491 492 border-right: 5px solid @grey6;
492 493 border-left: 0;
493 494 text-align: right;
494 495
495 496 // Account for citation
496 497 footer,
497 498 small,
498 499 .small {
499 500 &:before { content: ''; }
500 501 &:after {
501 502 content: '\00A0 \2014'; // nbsp, em dash
502 503 }
503 504 }
504 505 }
505 506
506 507 // Addresses
507 508 address {
508 509 margin-bottom: 2em;
509 510 font-style: normal;
510 511 line-height: 1.8em;
511 512 }
512 513
513 514 .error-message {
514 515 display: block;
515 516 margin: @padding/3 0;
516 517 color: @alert2;
517 518 }
518 519
519 520 .issue-tracker-link {
520 521 color: @rcblue;
521 522 }
522 523
523 524 .info_text{
524 525 font-size: @basefontsize;
525 526 color: @grey4;
526 527 font-family: @text-regular;
527 528 }
528 529
529 530 // help block text
530 531 .help-block {
531 532 display: block;
532 533 margin: 0 0 @padding;
533 534 color: @grey4;
534 535 font-family: @text-light;
535 536 }
536 537
537 538 .error-message {
538 539 display: block;
539 540 margin: @padding/3 0;
540 541 color: @alert2;
541 542 }
@@ -1,304 +1,306 b''
1 1 /*
2 2 * jQuery Commits Graph - v0.1.4
3 3 * A jQuery plugin to display git commits graph using HTML5/Canvas.
4 4 * https://github.com/tclh123/commits-graph
5 5 *
6 6 * Copyright (c) 2014
7 7 * MIT License
8 8 *
9 9 * Adapted to fit RhodeCode Enterprise changelog graph needs
10 10 */
11 11 // -- Route --------------------------------------------------------
12 12
13 13 function Route( commit, data, options ) {
14 14 var self = this;
15 15
16 16 self._data = data;
17 17 self.commit = commit;
18 18 self.options = options;
19 19 self.from = data[0];
20 20 self.to = data[1];
21 21 self.branch = data[2];
22 22 }
23 23
24 Route.prototype.drawRoute = function ( ctx ) {
24 Route.prototype.drawRoute = function ( commit, ctx ) {
25 25 var self = this;
26 26
27 27 if (self.options.orientation === "horizontal") {
28 28 var from_x_hori = self.options.width * self.options.scaleFactor - (self.commit.idx + 0.5) * self.options.x_step * self.options.scaleFactor;
29 29 var from_y_hori = (self.from + 1) * self.options.y_step * self.options.scaleFactor;
30 30
31 31 var to_x_hori = self.options.width * self.options.scaleFactor - (self.commit.idx + 0.5 + 1) * self.options.x_step * self.options.scaleFactor;
32 32 var to_y_hori = (self.to + 1) * self.options.y_step * self.options.scaleFactor;
33 33
34 34 ctx.strokeStyle = self.commit.graph.get_color(self.branch);
35 35 ctx.beginPath();
36 36 ctx.moveTo(from_x_hori, from_y_hori);
37 37 if (from_y_hori === to_y_hori) {
38 38 ctx.lineTo(to_x_hori, to_y_hori);
39 39 } else if (from_y_hori > to_y_hori) {
40 40 ctx.bezierCurveTo(from_x_hori - self.options.x_step * self.options.scaleFactor / 3 * 2,
41 41 from_y_hori + self.options.y_step * self.options.scaleFactor / 4,
42 42 to_x_hori + self.options.x_step * self.options.scaleFactor / 3 * 2,
43 43 to_y_hori - self.options.y_step * self.options.scaleFactor / 4,
44 44 to_x_hori, to_y_hori);
45 45 } else if (from_y_hori < to_y_hori) {
46 46 ctx.bezierCurveTo(from_x_hori - self.options.x_step * self.options.scaleFactor / 3 * 2,
47 47 from_y_hori - self.options.y_step * self.options.scaleFactor / 4,
48 48 to_x_hori + self.options.x_step * self.options.scaleFactor / 3 * 2,
49 49 to_y_hori + self.options.y_step * self.options.scaleFactor / 4,
50 50 to_x_hori, to_y_hori);
51 51 }
52 52
53 53 } else {
54 54 var from_x = self.options.width * self.options.scaleFactor - (self.from + 1) * self.options.x_step * self.options.scaleFactor;
55 var row = $("#chg_"+(self.commit.idx+1))
55 var row = $("#sha_" + commit.sha);
56 56 if (row.length) {
57 57 var from_y = (row.offset().top + row.height() / 2 - self.options.relaOffset) * self.options.scaleFactor;
58 58 }
59 59 var to_x = self.options.width * self.options.scaleFactor - (self.to + 1) * self.options.x_step * self.options.scaleFactor;
60 var next_row = $("#chg_"+(self.commit.idx+2))
60 var next_row = $("#sha_" + commit.sha).next('tr');
61
61 62 if (next_row.length) {
62 63 var to_y = ((next_row.offset().top + next_row.height() / 2 - self.options.relaOffset) + 0.2) * self.options.scaleFactor;
63 64 }
64 65
65 66 ctx.strokeStyle = self.commit.graph.get_color(self.branch);
66 67 ctx.beginPath();
67 68 ctx.moveTo(from_x, from_y);
68 69 if (from_x === to_x) {
69 70 ctx.lineTo(to_x, to_y);
70 71 } else {
71 72 ctx.bezierCurveTo(from_x - self.options.x_step * self.options.scaleFactor / 4,
72 73 from_y + self.options.y_step * self.options.scaleFactor / 3 * 2,
73 74 to_x + self.options.x_step * self.options.scaleFactor / 4,
74 75 to_y - self.options.y_step * self.options.scaleFactor / 3 * 2,
75 76 to_x, to_y);
76 77 }
77 78 }
78 79
79 80 ctx.stroke();
80 81 };
81 82
82 83 // -- Commit Node --------------------------------------------------------
83 84
84 85 function Commit(graph, idx, data, options ) {
85 86 var self = this;
86 87
87 88 self._data = data;
88 89 self.graph = graph;
89 90 self.idx = idx;
90 91 self.options = options;
91 92 self.sha = data[0];
92 93 self.dot = data[1];
93 94 self.dot_offset = self.dot[0];
94 95 self.dot_branch = self.dot[1];
95 96 self.routes = $.map(data[2], function(e) { return new Route(self, e, options); });
96 97 }
97 98
98 99 Commit.prototype.drawDot = function ( ctx ) {
99 100 var self = this;
100 101 var radius = self.options.dotRadius; // dot radius
101 102
102 103 if (self.options.orientation === "horizontal") {
103 104 var x_hori = self.options.width * self.options.scaleFactor - (self.idx + 0.5) * self.options.x_step * self.options.scaleFactor;
104 105 var y_hori = (self.dot_offset + 1) * self.options.y_step * self.options.scaleFactor;
105 106 ctx.fillStyle = self.graph.get_color(self.dot_branch);
106 107 ctx.beginPath();
107 108 ctx.arc(x_hori, y_hori, radius * self.options.scaleFactor, 0, 2 * Math.PI, true);
108 109
109 110 } else {
110 111 var x = self.options.width * self.options.scaleFactor - (self.dot_offset + 1) * self.options.x_step * self.options.scaleFactor;
111 var row = $("#chg_"+(self.idx+1))
112 var row = $("#sha_" + self.sha);
113
112 114 var y = (row.offset().top + row.height() / 2 - self.options.relaOffset) * self.options.scaleFactor;
113 115 ctx.fillStyle = self.graph.get_color(self.dot_branch);
114 116 ctx.beginPath();
115 117 ctx.arc(x, y, radius * self.options.scaleFactor, 0, 2 * Math.PI, true);
116 118 }
117 119 // ctx.stroke();
118 120 ctx.fill();
119 121 };
120 122
121 123 // -- Graph Canvas --------------------------------------------------------
122 124
123 125 function backingScale() {
124 126 if ('devicePixelRatio' in window) {
125 127 if (window.devicePixelRatio > 1) {
126 128 return window.devicePixelRatio;
127 129 }
128 130 }
129 131 return 1;
130 132 }
131 133
132 134 function GraphCanvas( data, options ) {
133 135 var self = this;
134 136
135 137 self.data = data;
136 138 self.options = options;
137 139 self.canvas = document.createElement("canvas");
138 140 self.canvas.style.height = options.height + "px";
139 141 self.canvas.style.width = options.width + "px";
140 142 self.canvas.height = options.height;
141 143 self.canvas.width = options.width;
142 144
143 145 var scaleFactor = backingScale();
144 146 if (self.options.orientation === "horizontal") {
145 147 if (scaleFactor < 1) {
146 148 self.canvas.width = self.canvas.width * scaleFactor;
147 149 self.canvas.height = self.canvas.height * scaleFactor;
148 150 }
149 151 } else {
150 152 if (scaleFactor > 1) {
151 153 self.canvas.width = self.canvas.width * scaleFactor;
152 154 self.canvas.height = self.canvas.height * scaleFactor;
153 155 }
154 156 }
155 157
156 158 self.options.scaleFactor = scaleFactor;
157 159
158 160 // or use context.scale(2,2) // not tested
159 161
160 162 self.colors = [
161 163 "#e11d21",
162 164 //"#eb6420",
163 165 "#fbca04",
164 166 "#009800",
165 167 "#006b75",
166 168 "#207de5",
167 169 "#0052cc",
168 170 "#5319e7",
169 171 "#f7c6c7",
170 172 "#fad8c7",
171 173 "#fef2c0",
172 174 "#bfe5bf",
173 175 "#c7def8",
174 176 "#bfdadc",
175 177 "#bfd4f2",
176 178 "#d4c5f9",
177 179 "#cccccc",
178 180 "#84b6eb",
179 181 "#e6e6e6",
180 182 "#ffffff",
181 183 "#cc317c"
182 184 ];
183 185 // self.branch_color = {};
184 186 }
185 187
186 188 GraphCanvas.prototype.toHTML = function () {
187 189 var self = this;
188 190
189 191 self.draw();
190 192
191 193 return $(self.canvas);
192 194 };
193 195
194 196 GraphCanvas.prototype.get_color = function (branch) {
195 197 var self = this;
196 198
197 199 var n = self.colors.length;
198 200 return self.colors[branch % n];
199 201 };
200 202
201 203 /*
202 204
203 205 [
204 206 sha,
205 207 [offset, branch], //dot
206 208 [
207 209 [from, to, branch], // route1
208 210 [from, to, branch], // route2
209 211 [from, to, branch],
210 212 ] // routes
211 213 ],
212 214
213 215 */
214 216 // draw
215 217 GraphCanvas.prototype.draw = function () {
216 218 var self = this,
217 219 ctx = self.canvas.getContext("2d");
218 220
219 221 ctx.lineWidth = self.options.lineWidth;
220 222
221 self.options.relaOffset = $("#chg_1").offset().top;
223 self.options.relaOffset = $(".changelogRow").first().offset().top;
222 224
223 225 var n_commits = self.data.length;
224 226 for (var i=0; i<n_commits; i++) {
225 227 var commit = new Commit(self, i, self.data[i], self.options);
226 228
227 229 for (var j=0; j<commit.routes.length; j++) {
228 230 var route = commit.routes[j];
229 route.drawRoute(ctx);
231 route.drawRoute(commit, ctx);
230 232 }
231 233 commit.drawDot(ctx);
232 234 }
233 235 };
234 236
235 237 // -- Function for finding the total number of branches -----------------------
236 238 branchCount = function(data) {
237 239 var maxBranch = -1;
238 240 for (var i = 0; i < data.length; i++) {
239 241 for (var j = 0; j < data[i][2].length; j++) {
240 242 if (maxBranch < data[i][2][j][0] || maxBranch < data[i][2][j][1]) {
241 243 maxBranch = Math.max.apply(Math, [data[i][2][j][0], data[i][2][j][1]]);
242 244 }
243 245 }
244 246 }
245 247 return maxBranch + 1;
246 248 };
247 249
248 250 // -- Graph Plugin ------------------------------------------------------------
249 251
250 252 function Graph( element, options ) {
251 253 var self = this,
252 254 defaults = {
253 255 height: 800,
254 256 width: 200,
255 257 // y_step: 30,
256 258 y_step: 20,
257 259 x_step: 20,
258 260 orientation: "vertical",
259 261 dotRadius: 3,
260 262 lineWidth: 2,
261 263 };
262 264
263 265 self.element = element;
264 266 self.$container = $( element );
265 267 self.data = self.$container.data( "graph" );
266 268
267 269 var x_step = $.extend( {}, defaults, options ).x_step;
268 270 var y_step = $.extend( {}, defaults, options ).y_step;
269 271
270 272 if (options.orientation === "horizontal") {
271 273 defaults.width = ( self.data.length + 2 ) * x_step;
272 274 defaults.height = ( branchCount(self.data) + 0.5 ) * y_step;
273 275 } else {
274 276 defaults.width = ( branchCount(self.data) + 0.5 ) * x_step;
275 277 defaults.height = ( self.data.length + 2 ) * y_step;
276 278 }
277 279
278 280 self.options = $.extend( {}, defaults, options ) ;
279 281
280 282 self._defaults = defaults;
281 283
282 284 self.applyTemplate();
283 285 }
284 286
285 287 // Apply results to HTML template
286 288 Graph.prototype.applyTemplate = function () {
287 289 var self = this,
288 290 graphCanvas = new GraphCanvas( self.data, self.options ),
289 291 $canvas = graphCanvas.toHTML();
290 292
291 293 $canvas.appendTo( self.$container );
292 294 };
293 295
294 296 // -- Attach plugin to jQuery's prototype --------------------------------------
295 297
296 298 ;( function ( $, window, undefined ) {
297 299
298 300 $.fn.commits = function ( options ) {
299 301 return this.each(function () {
300 302 $( this ).data( "plugin_commits_graph", new Graph( this, options ) );
301 303 });
302 304 };
303 305
304 306 }( window.jQuery, window ) );
@@ -1,56 +1,57 b''
1 1
2 2 /******************************************************************************
3 3 * *
4 4 * DO NOT CHANGE THIS FILE MANUALLY *
5 5 * *
6 6 * *
7 7 * This file is automatically generated when the app starts up with *
8 8 * generate_js_files = true *
9 9 * *
10 10 * To add a route here pass jsroute=True to the route definition in the app *
11 11 * *
12 12 ******************************************************************************/
13 13 function registerRCRoutes() {
14 14 // routes registration
15 15 pyroutes.register('home', '/', []);
16 16 pyroutes.register('user_autocomplete_data', '/_users', []);
17 17 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
18 18 pyroutes.register('new_repo', '/_admin/create_repository', []);
19 19 pyroutes.register('edit_user', '/_admin/users/%(user_id)s/edit', ['user_id']);
20 20 pyroutes.register('edit_user_group_members', '/_admin/user_groups/%(user_group_id)s/edit/members', ['user_group_id']);
21 21 pyroutes.register('gists', '/_admin/gists', []);
22 22 pyroutes.register('new_gist', '/_admin/gists/new', []);
23 23 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
24 24 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
25 25 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
26 26 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
27 27 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/default-reviewers', ['repo_name']);
28 28 pyroutes.register('changeset_home', '/%(repo_name)s/changeset/%(revision)s', ['repo_name', 'revision']);
29 29 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
30 30 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
31 31 pyroutes.register('changeset_comment', '/%(repo_name)s/changeset/%(revision)s/comment', ['repo_name', 'revision']);
32 32 pyroutes.register('changeset_comment_preview', '/%(repo_name)s/changeset/comment/preview', ['repo_name']);
33 33 pyroutes.register('changeset_comment_delete', '/%(repo_name)s/changeset/comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
34 34 pyroutes.register('changeset_info', '/%(repo_name)s/changeset_info/%(revision)s', ['repo_name', 'revision']);
35 35 pyroutes.register('compare_url', '/%(repo_name)s/compare/%(source_ref_type)s@%(source_ref)s...%(target_ref_type)s@%(target_ref)s', ['repo_name', 'source_ref_type', 'source_ref', 'target_ref_type', 'target_ref']);
36 36 pyroutes.register('pullrequest_home', '/%(repo_name)s/pull-request/new', ['repo_name']);
37 37 pyroutes.register('pullrequest', '/%(repo_name)s/pull-request/new', ['repo_name']);
38 38 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
39 39 pyroutes.register('pullrequest_repo_destinations', '/%(repo_name)s/pull-request/repo-destinations', ['repo_name']);
40 40 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
41 41 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
42 42 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
43 43 pyroutes.register('pullrequest_comment', '/%(repo_name)s/pull-request-comment/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
44 44 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request-comment/%(comment_id)s/delete', ['repo_name', 'comment_id']);
45 45 pyroutes.register('changelog_home', '/%(repo_name)s/changelog', ['repo_name']);
46 46 pyroutes.register('changelog_file_home', '/%(repo_name)s/changelog/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
47 pyroutes.register('changelog_elements', '/%(repo_name)s/changelog_details', ['repo_name']);
47 48 pyroutes.register('files_home', '/%(repo_name)s/files/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
48 49 pyroutes.register('files_history_home', '/%(repo_name)s/history/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
49 50 pyroutes.register('files_authors_home', '/%(repo_name)s/authors/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
50 51 pyroutes.register('files_annotate_home', '/%(repo_name)s/annotate/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
51 52 pyroutes.register('files_archive_home', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
52 53 pyroutes.register('files_nodelist_home', '/%(repo_name)s/nodelist/%(revision)s/%(f_path)s', ['repo_name', 'revision', 'f_path']);
53 54 pyroutes.register('files_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
54 55 pyroutes.register('summary_home_slash', '/%(repo_name)s/', ['repo_name']);
55 56 pyroutes.register('summary_home', '/%(repo_name)s', ['repo_name']);
56 57 }
@@ -1,440 +1,299 b''
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 <%inherit file="/base/base.mako"/>
4 4
5 5 <%def name="title()">
6 6 ${_('%s Changelog') % c.repo_name}
7 7 %if c.changelog_for_path:
8 8 /${c.changelog_for_path}
9 9 %endif
10 10 %if c.rhodecode_name:
11 11 &middot; ${h.branding(c.rhodecode_name)}
12 12 %endif
13 13 </%def>
14 14
15 15 <%def name="breadcrumbs_links()">
16 16 %if c.changelog_for_path:
17 17 /${c.changelog_for_path}
18 18 %endif
19 ${ungettext('showing %d out of %d commit', 'showing %d out of %d commits', c.showing_commits) % (c.showing_commits, c.total_cs)}
20 19 </%def>
21 20
22 21 <%def name="menu_bar_nav()">
23 22 ${self.menu_items(active='repositories')}
24 23 </%def>
25 24
26 25 <%def name="menu_bar_subnav()">
27 26 ${self.repo_menu(active='changelog')}
28 27 </%def>
29 28
30 29 <%def name="main()">
31 30
32 31 <div class="box">
33 32 <div class="title">
34 33 ${self.repo_page_title(c.rhodecode_db_repo)}
35 34 <ul class="links">
36 35 <li>
37 36 <a href="#" class="btn btn-small" id="rev_range_container" style="display:none;"></a>
38 37 %if c.rhodecode_db_repo.fork:
39 38 <span>
40 39 <a id="compare_fork_button"
41 40 title="${_('Compare fork with %s' % c.rhodecode_db_repo.fork.repo_name)}"
42 41 class="btn btn-small"
43 42 href="${h.url('compare_url',
44 43 repo_name=c.rhodecode_db_repo.fork.repo_name,
45 44 source_ref_type=c.rhodecode_db_repo.landing_rev[0],
46 45 source_ref=c.rhodecode_db_repo.landing_rev[1],
47 46 target_repo=c.repo_name,
48 47 target_ref_type='branch' if request.GET.get('branch') else c.rhodecode_db_repo.landing_rev[0],
49 48 target_ref=request.GET.get('branch') or c.rhodecode_db_repo.landing_rev[1],
50 49 merge=1)}"
51 50 >
52 51 <i class="icon-loop"></i>
53 52 ${_('Compare fork with Parent (%s)' % c.rhodecode_db_repo.fork.repo_name)}
54 53 </a>
55 54 </span>
56 55 %endif
57 56
58 57 ## pr open link
59 58 %if h.is_hg(c.rhodecode_repo) or h.is_git(c.rhodecode_repo):
60 59 <span>
61 60 <a id="open_new_pull_request" class="btn btn-small btn-success" href="${h.url('pullrequest_home',repo_name=c.repo_name)}">
62 61 ${_('Open new pull request')}
63 62 </a>
64 63 </span>
65 64 %endif
66 65
67 66 ## clear selection
68 67 <div title="${_('Clear selection')}" class="btn" id="rev_range_clear" style="display:none">
69 68 ${_('Clear selection')}
70 69 </div>
71 70
72 71 </li>
73 72 </ul>
74 73 </div>
75 74
76 75 % if c.pagination:
76 <script type="text/javascript" src="${h.asset('js/jquery.commits-graph.js')}"></script>
77 77
78 78 <div class="graph-header">
79 79 <div id="filter_changelog">
80 80 ${h.hidden('branch_filter')}
81 81 %if c.selected_name:
82 82 <div class="btn btn-default" id="clear_filter" >
83 83 ${_('Clear filter')}
84 84 </div>
85 85 %endif
86 86 </div>
87 87 ${self.breadcrumbs('breadcrumbs_light')}
88 <div id="commit-counter" data-total=${c.total_cs} class="pull-right">
89 ${ungettext('showing %d out of %d commit', 'showing %d out of %d commits', c.showing_commits) % (c.showing_commits, c.total_cs)}
90 </div>
88 91 </div>
89 92
90 <div id="graph">
91 <div class="graph-col-wrapper">
92 <div id="graph_nodes">
93 <div id="graph_canvas" data-graph='${c.jsdata|n}'></div>
94 </div>
95 <div id="graph_content" class="main-content graph_full_width">
96
97 <div class="table">
98 <table id="changesets" class="rctable">
99 <tr>
100 ## checkbox
101 <th></th>
102 <th colspan="2"></th>
93 <div id="graph">
94 <div class="graph-col-wrapper">
95 <div id="graph_nodes">
96 <div id="graph_canvas"></div>
97 </div>
98 <div id="graph_content" class="main-content graph_full_width">
103 99
104 <th>${_('Commit')}</th>
105 ## commit message expand arrow
106 <th></th>
107 <th>${_('Commit Message')}</th>
108
109 <th>${_('Age')}</th>
110 <th>${_('Author')}</th>
100 <div class="table">
101 <table id="changesets" class="rctable">
102 <tr>
103 ## checkbox
104 <th></th>
105 <th colspan="2"></th>
111 106
112 <th>${_('Refs')}</th>
113 </tr>
114 <tbody>
115 %for cnt,commit in enumerate(c.pagination):
116 <tr id="chg_${cnt+1}" class="container ${'tablerow%s' % (cnt%2)}">
117
118 <td class="td-checkbox">
119 ${h.checkbox(commit.raw_id,class_="commit-range")}
120 </td>
121 <td class="td-status">
107 <th>${_('Commit')}</th>
108 ## commit message expand arrow
109 <th></th>
110 <th>${_('Commit Message')}</th>
122 111
123 %if c.statuses.get(commit.raw_id):
124 <div class="changeset-status-ico">
125 %if c.statuses.get(commit.raw_id)[2]:
126 <a class="tooltip" title="${_('Commit status: %s\nClick to open associated pull request #%s') % (h.commit_status_lbl(c.statuses.get(commit.raw_id)[0]), c.statuses.get(commit.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(commit.raw_id)[3],pull_request_id=c.statuses.get(commit.raw_id)[2])}">
127 <div class="${'flag_status %s' % c.statuses.get(commit.raw_id)[0]}"></div>
128 </a>
129 %else:
130 <a class="tooltip" title="${_('Commit status: %s') % h.commit_status_lbl(c.statuses.get(commit.raw_id)[0])}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id,anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
131 <div class="${'flag_status %s' % c.statuses.get(commit.raw_id)[0]}"></div>
132 </a>
133 %endif
134 </div>
135 %else:
136 <div class="tooltip flag_status not_reviewed" title="${_('Commit status: Not Reviewed')}"></div>
137 %endif
138 </td>
139 <td class="td-comments comments-col">
140 %if c.comments.get(commit.raw_id):
141 <a title="${_('Commit has comments')}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id,anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
142 <i class="icon-comment"></i> ${len(c.comments[commit.raw_id])}
143 </a>
144 %endif
145 </td>
146 <td class="td-hash">
147 <code>
148 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">
149 <span class="commit_hash">${h.show_id(commit)}</span>
150 </a>
151 </code>
152 </td>
153 <td class="td-message expand_commit" data-commit-id="${commit.raw_id}" title="${_('Expand commit message')}">
154 <div class="show_more_col">
155 <i class="show_more"></i>&nbsp;
156 </div>
157 </td>
158 <td class="td-description mid">
159 <div class="log-container truncate-wrap">
160 <div class="message truncate" id="c-${commit.raw_id}">${h.urlify_commit_message(commit.message, c.repo_name)}</div>
161 </div>
162 </td>
112 <th>${_('Age')}</th>
113 <th>${_('Author')}</th>
114
115 <th>${_('Refs')}</th>
116 </tr>
163 117
164 <td class="td-time">
165 ${h.age_component(commit.date)}
166 </td>
167 <td class="td-user">
168 ${self.gravatar_with_user(commit.author)}
169 </td>
170
171 <td class="td-tags tags-col">
172 <div id="t-${commit.raw_id}">
173 ## branch
174 %if commit.branch:
175 <span class="branchtag tag" title="${_('Branch %s') % commit.branch}">
176 <a href="${h.url('changelog_home',repo_name=c.repo_name,branch=commit.branch)}"><i class="icon-code-fork"></i>${h.shorter(commit.branch)}</a>
177 </span>
178 %endif
118 <tbody class="commits-range">
119 <%include file='changelog_elements.mako'/>
120 </tbody>
121 </table>
122 </div>
123 </div>
124 <div class="pagination-wh pagination-left">
125 ${c.pagination.pager('$link_previous ~2~ $link_next')}
126 </div>
127 </div>
179 128
180 ## bookmarks
181 %if h.is_hg(c.rhodecode_repo):
182 %for book in commit.bookmarks:
183 <span class="tag booktag" title="${_('Bookmark %s') % book}">
184 <a href="${h.url('files_home',repo_name=c.repo_name,revision=commit.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a>
185 </span>
186 %endfor
187 %endif
188
189 ## tags
190 %for tag in commit.tags:
191 <span class="tagtag tag" title="${_('Tag %s') % tag}">
192 <a href="${h.url('files_home',repo_name=c.repo_name,revision=commit.raw_id)}"><i class="icon-tag"></i>${h.shorter(tag)}</a>
193 </span>
194 %endfor
195
196 </div>
197 </td>
198 </tr>
199 %endfor
200 </tbody>
201 </table>
202 </div>
203 </div>
204 </div>
205 <div class="pagination-wh pagination-left">
206 ${c.pagination.pager('$link_previous ~2~ $link_next')}
207 </div>
208
209 <script type="text/javascript" src="${h.asset('js/jquery.commits-graph.js')}"></script>
210 <script type="text/javascript">
129 <script type="text/javascript">
211 130 var cache = {};
212 131 $(function(){
213 132
214 133 // Create links to commit ranges when range checkboxes are selected
215 var $commitCheckboxes = $('.commit-range');
134 var $commitCheckboxes = $('.commit-range');
216 135 // cache elements
217 136 var $commitRangeContainer = $('#rev_range_container');
218 137 var $commitRangeClear = $('#rev_range_clear');
219 138
220 139 var checkboxRangeSelector = function(e){
221 140 var selectedCheckboxes = [];
222 141 for (pos in $commitCheckboxes){
223 142 if($commitCheckboxes[pos].checked){
224 143 selectedCheckboxes.push($commitCheckboxes[pos]);
225 144 }
226 145 }
227 146 var open_new_pull_request = $('#open_new_pull_request');
228 147 if(open_new_pull_request){
229 148 var selected_changes = selectedCheckboxes.length;
230 149 if (selected_changes > 1 || selected_changes == 1 && templateContext.repo_type != 'hg') {
231 150 open_new_pull_request.hide();
232 151 } else {
233 152 if (selected_changes == 1) {
234 153 open_new_pull_request.html(_gettext('Open new pull request for selected commit'));
235 154 } else if (selected_changes == 0) {
236 155 open_new_pull_request.html(_gettext('Open new pull request'));
237 156 }
238 157 open_new_pull_request.show();
239 158 }
240 159 }
241 160
242 161 if (selectedCheckboxes.length>0){
243 162 var revEnd = selectedCheckboxes[0].name;
244 163 var revStart = selectedCheckboxes[selectedCheckboxes.length-1].name;
245 164 var url = pyroutes.url('changeset_home',
246 165 {'repo_name': '${c.repo_name}',
247 166 'revision': revStart+'...'+revEnd});
248 167
249 168 var link = (revStart == revEnd)
250 169 ? _gettext('Show selected commit __S')
251 170 : _gettext('Show selected commits __S ... __E');
252 171
253 172 link = link.replace('__S', revStart.substr(0,6));
254 173 link = link.replace('__E', revEnd.substr(0,6));
255 174
256 175 $commitRangeContainer
257 176 .attr('href',url)
258 177 .html(link)
259 178 .show();
260 179
261 180 $commitRangeClear.show();
262 181 var _url = pyroutes.url('pullrequest_home',
263 182 {'repo_name': '${c.repo_name}',
264 183 'commit': revEnd});
265 184 open_new_pull_request.attr('href', _url);
266 185 $('#compare_fork_button').hide();
267 186 } else {
268 187 $commitRangeContainer.hide();
269 188 $commitRangeClear.hide();
270 189
271 190 %if c.branch_name:
272 191 var _url = pyroutes.url('pullrequest_home',
273 192 {'repo_name': '${c.repo_name}',
274 193 'branch':'${c.branch_name}'});
275 194 open_new_pull_request.attr('href', _url);
276 195 %else:
277 196 var _url = pyroutes.url('pullrequest_home',
278 197 {'repo_name': '${c.repo_name}'});
279 198 open_new_pull_request.attr('href', _url);
280 199 %endif
281 200 $('#compare_fork_button').show();
282 201 }
283 202 };
284 203
285 204 $commitCheckboxes.on('click', checkboxRangeSelector);
286 205
287 206 $commitRangeClear.on('click',function(e) {
288 207 $commitCheckboxes.attr('checked', false);
289 208 checkboxRangeSelector();
290 209 e.preventDefault();
291 210 });
292 211
293 212 // make sure the buttons are consistent when navigate back and forth
294 213 checkboxRangeSelector();
295 214
296
297 215 var msgs = $('.message');
298 216 // get first element height
299 217 var el = $('#graph_content .container')[0];
300 218 var row_h = el.clientHeight;
301 219 for (var i=0; i < msgs.length; i++) {
302 220 var m = msgs[i];
303 221
304 222 var h = m.clientHeight;
305 223 var pad = $(m).css('padding');
306 224 if (h > row_h) {
307 225 var offset = row_h - (h+12);
308 226 $(m.nextElementSibling).css('display','block');
309 227 $(m.nextElementSibling).css('margin-top',offset+'px');
310 228 }
311 229 }
312 230
313 $('.expand_commit').on('click', function (e) {
314 var target_expand = $(this);
315 var cid = target_expand.data('commitId');
316
317 if (target_expand.hasClass('open')) {
318 $('#c-' + cid).css({
319 'height': '1.5em',
320 'white-space': 'nowrap',
321 'text-overflow': 'ellipsis',
322 'overflow': 'hidden'
323 });
324 $('#t-' + cid).css({
325 'height': 'auto',
326 'line-height': '.9em',
327 'text-overflow': 'ellipsis',
328 'overflow': 'hidden',
329 'white-space': 'nowrap'
330 });
331 target_expand.removeClass('open');
332 }
333 else {
334 $('#c-' + cid).css({
335 'height': 'auto',
336 'white-space': 'pre-line',
337 'text-overflow': 'initial',
338 'overflow': 'visible'
339 });
340 $('#t-' + cid).css({
341 'height': 'auto',
342 'max-height': 'none',
343 'text-overflow': 'initial',
344 'overflow': 'visible',
345 'white-space': 'normal'
346 });
347 target_expand.addClass('open');
348 }
349 // redraw the graph
350 graph_options.height = $("#changesets").height();
351 $("canvas").remove();
352 $("[data-graph]").commits(graph_options);
353 });
354
355 231 $("#clear_filter").on("click", function() {
356 232 var filter = {'repo_name': '${c.repo_name}'};
357 233 window.location = pyroutes.url('changelog_home', filter);
358 234 });
359 235
360 236 $("#branch_filter").select2({
361 237 'dropdownAutoWidth': true,
362 238 'width': 'resolve',
363 239 'placeholder': "${c.selected_name or _('Filter changelog')}",
364 240 containerCssClass: "drop-menu",
365 241 dropdownCssClass: "drop-menu-dropdown",
366 242 query: function(query){
367 243 var key = 'cache';
368 244 var cached = cache[key] ;
369 245 if(cached) {
370 246 var data = {results: []};
371 247 //filter results
372 248 $.each(cached.results, function(){
373 249 var section = this.text;
374 250 var children = [];
375 251 $.each(this.children, function(){
376 252 if(query.term.length == 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
377 253 children.push({'id': this.id, 'text': this.text, 'type': this.type})
378 254 }
379 255 });
380 256 data.results.push({'text': section, 'children': children});
381 257 query.callback({results: data.results});
382 258 });
383 259 }else{
384 260 $.ajax({
385 261 url: pyroutes.url('repo_refs_changelog_data', {'repo_name': '${c.repo_name}'}),
386 262 data: {},
387 263 dataType: 'json',
388 264 type: 'GET',
389 265 success: function(data) {
390 266 cache[key] = data;
391 267 query.callback({results: data.results});
392 268 }
393 269 })
394 270 }
395 271 }
396 272 });
397
398 273 $('#branch_filter').on('change', function(e){
399 274 var data = $('#branch_filter').select2('data');
400 275 var selected = data.text;
401 276 var filter = {'repo_name': '${c.repo_name}'};
402 277 if(data.type == 'branch' || data.type == 'branch_closed'){
403 278 filter["branch"] = selected;
404 279 }
405 280 else if (data.type == 'book'){
406 281 filter["bookmark"] = selected;
407 282 }
408 283 window.location = pyroutes.url('changelog_home', filter);
409 284 });
410 285
411 // Determine max number of edges per row in graph
412 var jsdata = $.parseJSON($("[data-graph]").attr('data-graph'));
413 var edgeCount = 1;
414 $.each(jsdata, function(i, item){
415 $.each(item[2], function(key, value) {
416 if (value[1] > edgeCount){
417 edgeCount = value[1];
418 }
419 });
420 });
421 var x_step = Math.min(18, Math.floor(86 / edgeCount));
422 var graph_options = {
423 width: 100,
424 height: $("#changesets").height(),
425 x_step: x_step,
426 y_step: 42,
427 dotRadius: 3.5,
428 lineWidth: 2.5
429 };
430 $("[data-graph]").commits(graph_options);
286 commitsController = new CommitsController();
287 % if not c.changelog_for_path:
288 commitsController.reloadGraph();
289 % endif
431 290
432 291 });
433 292
434 293 </script>
435 %else:
294 </div>
295 % else:
436 296 ${_('There are no changes yet')}
437 %endif
438 </div>
297 % endif
439 298 </div>
440 299 </%def>
@@ -1,11 +1,122 b''
1 1 ## small box that displays changed/added/removed details fetched by AJAX
2 <%namespace name="base" file="/base/base.mako"/>
3
4
5 % if c.prev_page:
6 <tr>
7 <td colspan="9" class="load-more-commits">
8 <a class="prev-commits" href="#loadPrevCommits" onclick="commitsController.loadPrev(this, ${c.prev_page}, '${c.branch_name}');return false">
9 ${_('load previous')}
10 </a>
11 </td>
12 </tr>
13 % endif
14
15 % for cnt,commit in enumerate(c.pagination):
16 <tr id="sha_${commit.raw_id}" class="changelogRow container ${'tablerow%s' % (cnt%2)}">
17
18 <td class="td-checkbox">
19 ${h.checkbox(commit.raw_id,class_="commit-range")}
20 </td>
21 <td class="td-status">
2 22
3 % if len(c.commit.affected_files) <= c.affected_files_cut_off:
4 <span class="removed tooltip" title="<b>${h.tooltip(_('Removed'))}</b>${h.changed_tooltip(c.commit.removed)}">${len(c.commit.removed)}</span>
5 <span class="changed tooltip" title="<b>${h.tooltip(_('Changed'))}</b>${h.changed_tooltip(c.commit.changed)}">${len(c.commit.changed)}</span>
6 <span class="added tooltip" title="<b>${h.tooltip(_('Added'))}</b>${h.changed_tooltip(c.commit.added)}">${len(c.commit.added)}</span>
7 % else:
8 <span class="removed tooltip" title="${h.tooltip(_('Affected %s files') % len(c.commit.affected_files))}">!</span>
9 <span class="changed tooltip" title="${h.tooltip(_('Affected %s files') % len(c.commit.affected_files))}">!</span>
10 <span class="added tooltip" title="${h.tooltip(_('Affected %s files') % len(c.commit.affected_files))}">!</span>
23 %if c.statuses.get(commit.raw_id):
24 <div class="changeset-status-ico">
25 %if c.statuses.get(commit.raw_id)[2]:
26 <a class="tooltip" title="${_('Commit status: %s\nClick to open associated pull request #%s') % (h.commit_status_lbl(c.statuses.get(commit.raw_id)[0]), c.statuses.get(commit.raw_id)[2])}" href="${h.url('pullrequest_show',repo_name=c.statuses.get(commit.raw_id)[3],pull_request_id=c.statuses.get(commit.raw_id)[2])}">
27 <div class="${'flag_status %s' % c.statuses.get(commit.raw_id)[0]}"></div>
28 </a>
29 %else:
30 <a class="tooltip" title="${_('Commit status: %s') % h.commit_status_lbl(c.statuses.get(commit.raw_id)[0])}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id,anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
31 <div class="${'flag_status %s' % c.statuses.get(commit.raw_id)[0]}"></div>
32 </a>
33 %endif
34 </div>
35 %else:
36 <div class="tooltip flag_status not_reviewed" title="${_('Commit status: Not Reviewed')}"></div>
37 %endif
38 </td>
39 <td class="td-comments comments-col">
40 %if c.comments.get(commit.raw_id):
41 <a title="${_('Commit has comments')}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id,anchor='comment-%s' % c.comments[commit.raw_id][0].comment_id)}">
42 <i class="icon-comment"></i> ${len(c.comments[commit.raw_id])}
43 </a>
44 %endif
45 </td>
46 <td class="td-hash">
47 <code>
48 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">
49 <span class="commit_hash">${h.show_id(commit)}</span>
50 </a>
51 </code>
52 </td>
53 <td class="td-message expand_commit" data-commit-id="${commit.raw_id}" title="${_('Expand commit message')}" onclick="commitsController.expandCommit(this); return false">
54 <div class="show_more_col">
55 <i class="show_more"></i>&nbsp;
56 </div>
57 </td>
58 <td class="td-description mid">
59 <div class="log-container truncate-wrap">
60 <div class="message truncate" id="c-${commit.raw_id}">${h.urlify_commit_message(commit.message, c.repo_name)}</div>
61 </div>
62 </td>
63
64 <td class="td-time">
65 ${h.age_component(commit.date)}
66 </td>
67 <td class="td-user">
68 ${base.gravatar_with_user(commit.author)}
69 </td>
70
71 <td class="td-tags tags-col">
72 <div id="t-${commit.raw_id}">
73
74 ## merge
75 %if commit.merge:
76 <span class="tag mergetag">
77 <i class="icon-merge"></i>${_('merge')}
78 </span>
79 %endif
80
81 ## branch
82 %if commit.branch:
83 <span class="tag branchtag" title="${_('Branch %s') % commit.branch}">
84 <a href="${h.url('changelog_home',repo_name=c.repo_name,branch=commit.branch)}"><i class="icon-code-fork"></i>${h.shorter(commit.branch)}</a>
85 </span>
86 %endif
87
88 ## bookmarks
89 %if h.is_hg(c.rhodecode_repo):
90 %for book in commit.bookmarks:
91 <span class="tag booktag" title="${_('Bookmark %s') % book}">
92 <a href="${h.url('files_home',repo_name=c.repo_name,revision=commit.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a>
93 </span>
94 %endfor
95 %endif
96
97 ## tags
98 %for tag in commit.tags:
99 <span class="tag tagtag" title="${_('Tag %s') % tag}">
100 <a href="${h.url('files_home',repo_name=c.repo_name,revision=commit.raw_id)}"><i class="icon-tag"></i>${h.shorter(tag)}</a>
101 </span>
102 %endfor
103
104 </div>
105 </td>
106 </tr>
107 % endfor
108
109 % if c.next_page:
110 <tr>
111 <td colspan="9" class="load-more-commits">
112 <a class="next-commits" href="#loadNextCommits" onclick="commitsController.loadNext(this, ${c.next_page}, '${c.branch_name}');return false">
113 ${_('load next')}
114 </a>
115 </td>
116 </tr>
11 117 % endif
118 <tr class="chunk-graph-data" style="display:none"
119 data-graph='${c.graph_data|n}'
120 data-node='${c.prev_page}:${c.next_page}'
121 data-commits='${c.graph_commits|n}'>
122 </tr> No newline at end of file
@@ -1,45 +1,39 b''
1 1 <%namespace name="base" file="/base/base.mako"/>
2 2 <div class="table">
3 3
4 4 <table class="table rctable file_history">
5 5 %for cnt,cs in enumerate(c.pagination):
6 6 <tr id="chg_${cnt+1}" class="${'tablerow%s' % (cnt%2)}">
7 7 <td class="td-user">
8 8 ${base.gravatar_with_user(cs.author, 16)}
9 9 </td>
10 10 <td class="td-time">
11 11 <div class="date">
12 12 ${h.age_component(cs.date)}
13 13 </div>
14 14 </td>
15 15 <td class="td-message">
16 16 <div class="log-container">
17
18 %if cs.merge:
19 <span class="mergetag">
20 <i class="icon-merge"></i>${_('merge')}
21 </span>
22 %endif
23 17 <div class="message_history" title="${cs.message}">
24 18 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">
25 19 ${h.shorter(cs.message, 75)}
26 20 </a>
27 21 </div>
28 22 </div>
29 23 </td>
30 24 <td class="td-hash">
31 25 <code>
32 26 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=cs.raw_id)}">
33 27 <span>${h.show_id(cs)}</span>
34 28 </a>
35 29 </code>
36 30 </td>
37 31 <td class="td-actions">
38 32 <a href="${h.url('files_home',repo_name=c.repo_name,f_path=c.changelog_for_path,revision=cs.raw_id)}">
39 33 ${_('Show File')}
40 34 </a>
41 35 </td>
42 36 </tr>
43 37 %endfor
44 38 </table>
45 39 </div>
General Comments 0
You need to be logged in to leave comments. Login now