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