##// END OF EJS Templates
files: add pre-commit checks on file operations to prevent loosing content while editing when repositories change....
dan -
r4302:4c157b04 default
parent child Browse files
Show More
@@ -1,516 +1,520 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-2019 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 from rhodecode.apps._base import add_route_with_slash
20 from rhodecode.apps._base import add_route_with_slash
21
21
22
22
23 def includeme(config):
23 def includeme(config):
24
24
25 # repo creating checks, special cases that aren't repo routes
25 # repo creating checks, special cases that aren't repo routes
26 config.add_route(
26 config.add_route(
27 name='repo_creating',
27 name='repo_creating',
28 pattern='/{repo_name:.*?[^/]}/repo_creating')
28 pattern='/{repo_name:.*?[^/]}/repo_creating')
29
29
30 config.add_route(
30 config.add_route(
31 name='repo_creating_check',
31 name='repo_creating_check',
32 pattern='/{repo_name:.*?[^/]}/repo_creating_check')
32 pattern='/{repo_name:.*?[^/]}/repo_creating_check')
33
33
34 # Summary
34 # Summary
35 # NOTE(marcink): one additional route is defined in very bottom, catch
35 # NOTE(marcink): one additional route is defined in very bottom, catch
36 # all pattern
36 # all pattern
37 config.add_route(
37 config.add_route(
38 name='repo_summary_explicit',
38 name='repo_summary_explicit',
39 pattern='/{repo_name:.*?[^/]}/summary', repo_route=True)
39 pattern='/{repo_name:.*?[^/]}/summary', repo_route=True)
40 config.add_route(
40 config.add_route(
41 name='repo_summary_commits',
41 name='repo_summary_commits',
42 pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True)
42 pattern='/{repo_name:.*?[^/]}/summary-commits', repo_route=True)
43
43
44 # Commits
44 # Commits
45 config.add_route(
45 config.add_route(
46 name='repo_commit',
46 name='repo_commit',
47 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}', repo_route=True)
47 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}', repo_route=True)
48
48
49 config.add_route(
49 config.add_route(
50 name='repo_commit_children',
50 name='repo_commit_children',
51 pattern='/{repo_name:.*?[^/]}/changeset_children/{commit_id}', repo_route=True)
51 pattern='/{repo_name:.*?[^/]}/changeset_children/{commit_id}', repo_route=True)
52
52
53 config.add_route(
53 config.add_route(
54 name='repo_commit_parents',
54 name='repo_commit_parents',
55 pattern='/{repo_name:.*?[^/]}/changeset_parents/{commit_id}', repo_route=True)
55 pattern='/{repo_name:.*?[^/]}/changeset_parents/{commit_id}', repo_route=True)
56
56
57 config.add_route(
57 config.add_route(
58 name='repo_commit_raw',
58 name='repo_commit_raw',
59 pattern='/{repo_name:.*?[^/]}/changeset-diff/{commit_id}', repo_route=True)
59 pattern='/{repo_name:.*?[^/]}/changeset-diff/{commit_id}', repo_route=True)
60
60
61 config.add_route(
61 config.add_route(
62 name='repo_commit_patch',
62 name='repo_commit_patch',
63 pattern='/{repo_name:.*?[^/]}/changeset-patch/{commit_id}', repo_route=True)
63 pattern='/{repo_name:.*?[^/]}/changeset-patch/{commit_id}', repo_route=True)
64
64
65 config.add_route(
65 config.add_route(
66 name='repo_commit_download',
66 name='repo_commit_download',
67 pattern='/{repo_name:.*?[^/]}/changeset-download/{commit_id}', repo_route=True)
67 pattern='/{repo_name:.*?[^/]}/changeset-download/{commit_id}', repo_route=True)
68
68
69 config.add_route(
69 config.add_route(
70 name='repo_commit_data',
70 name='repo_commit_data',
71 pattern='/{repo_name:.*?[^/]}/changeset-data/{commit_id}', repo_route=True)
71 pattern='/{repo_name:.*?[^/]}/changeset-data/{commit_id}', repo_route=True)
72
72
73 config.add_route(
73 config.add_route(
74 name='repo_commit_comment_create',
74 name='repo_commit_comment_create',
75 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/create', repo_route=True)
75 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/create', repo_route=True)
76
76
77 config.add_route(
77 config.add_route(
78 name='repo_commit_comment_preview',
78 name='repo_commit_comment_preview',
79 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/preview', repo_route=True)
79 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/preview', repo_route=True)
80
80
81 config.add_route(
81 config.add_route(
82 name='repo_commit_comment_attachment_upload',
82 name='repo_commit_comment_attachment_upload',
83 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/attachment_upload', repo_route=True)
83 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/attachment_upload', repo_route=True)
84
84
85 config.add_route(
85 config.add_route(
86 name='repo_commit_comment_delete',
86 name='repo_commit_comment_delete',
87 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_id}/delete', repo_route=True)
87 pattern='/{repo_name:.*?[^/]}/changeset/{commit_id}/comment/{comment_id}/delete', repo_route=True)
88
88
89 # still working url for backward compat.
89 # still working url for backward compat.
90 config.add_route(
90 config.add_route(
91 name='repo_commit_raw_deprecated',
91 name='repo_commit_raw_deprecated',
92 pattern='/{repo_name:.*?[^/]}/raw-changeset/{commit_id}', repo_route=True)
92 pattern='/{repo_name:.*?[^/]}/raw-changeset/{commit_id}', repo_route=True)
93
93
94 # Files
94 # Files
95 config.add_route(
95 config.add_route(
96 name='repo_archivefile',
96 name='repo_archivefile',
97 pattern='/{repo_name:.*?[^/]}/archive/{fname:.*}', repo_route=True)
97 pattern='/{repo_name:.*?[^/]}/archive/{fname:.*}', repo_route=True)
98
98
99 config.add_route(
99 config.add_route(
100 name='repo_files_diff',
100 name='repo_files_diff',
101 pattern='/{repo_name:.*?[^/]}/diff/{f_path:.*}', repo_route=True)
101 pattern='/{repo_name:.*?[^/]}/diff/{f_path:.*}', repo_route=True)
102 config.add_route( # legacy route to make old links work
102 config.add_route( # legacy route to make old links work
103 name='repo_files_diff_2way_redirect',
103 name='repo_files_diff_2way_redirect',
104 pattern='/{repo_name:.*?[^/]}/diff-2way/{f_path:.*}', repo_route=True)
104 pattern='/{repo_name:.*?[^/]}/diff-2way/{f_path:.*}', repo_route=True)
105
105
106 config.add_route(
106 config.add_route(
107 name='repo_files',
107 name='repo_files',
108 pattern='/{repo_name:.*?[^/]}/files/{commit_id}/{f_path:.*}', repo_route=True)
108 pattern='/{repo_name:.*?[^/]}/files/{commit_id}/{f_path:.*}', repo_route=True)
109 config.add_route(
109 config.add_route(
110 name='repo_files:default_path',
110 name='repo_files:default_path',
111 pattern='/{repo_name:.*?[^/]}/files/{commit_id}/', repo_route=True)
111 pattern='/{repo_name:.*?[^/]}/files/{commit_id}/', repo_route=True)
112 config.add_route(
112 config.add_route(
113 name='repo_files:default_commit',
113 name='repo_files:default_commit',
114 pattern='/{repo_name:.*?[^/]}/files', repo_route=True)
114 pattern='/{repo_name:.*?[^/]}/files', repo_route=True)
115
115
116 config.add_route(
116 config.add_route(
117 name='repo_files:rendered',
117 name='repo_files:rendered',
118 pattern='/{repo_name:.*?[^/]}/render/{commit_id}/{f_path:.*}', repo_route=True)
118 pattern='/{repo_name:.*?[^/]}/render/{commit_id}/{f_path:.*}', repo_route=True)
119
119
120 config.add_route(
120 config.add_route(
121 name='repo_files:annotated',
121 name='repo_files:annotated',
122 pattern='/{repo_name:.*?[^/]}/annotate/{commit_id}/{f_path:.*}', repo_route=True)
122 pattern='/{repo_name:.*?[^/]}/annotate/{commit_id}/{f_path:.*}', repo_route=True)
123 config.add_route(
123 config.add_route(
124 name='repo_files:annotated_previous',
124 name='repo_files:annotated_previous',
125 pattern='/{repo_name:.*?[^/]}/annotate-previous/{commit_id}/{f_path:.*}', repo_route=True)
125 pattern='/{repo_name:.*?[^/]}/annotate-previous/{commit_id}/{f_path:.*}', repo_route=True)
126
126
127 config.add_route(
127 config.add_route(
128 name='repo_nodetree_full',
128 name='repo_nodetree_full',
129 pattern='/{repo_name:.*?[^/]}/nodetree_full/{commit_id}/{f_path:.*}', repo_route=True)
129 pattern='/{repo_name:.*?[^/]}/nodetree_full/{commit_id}/{f_path:.*}', repo_route=True)
130 config.add_route(
130 config.add_route(
131 name='repo_nodetree_full:default_path',
131 name='repo_nodetree_full:default_path',
132 pattern='/{repo_name:.*?[^/]}/nodetree_full/{commit_id}/', repo_route=True)
132 pattern='/{repo_name:.*?[^/]}/nodetree_full/{commit_id}/', repo_route=True)
133
133
134 config.add_route(
134 config.add_route(
135 name='repo_files_nodelist',
135 name='repo_files_nodelist',
136 pattern='/{repo_name:.*?[^/]}/nodelist/{commit_id}/{f_path:.*}', repo_route=True)
136 pattern='/{repo_name:.*?[^/]}/nodelist/{commit_id}/{f_path:.*}', repo_route=True)
137
137
138 config.add_route(
138 config.add_route(
139 name='repo_file_raw',
139 name='repo_file_raw',
140 pattern='/{repo_name:.*?[^/]}/raw/{commit_id}/{f_path:.*}', repo_route=True)
140 pattern='/{repo_name:.*?[^/]}/raw/{commit_id}/{f_path:.*}', repo_route=True)
141
141
142 config.add_route(
142 config.add_route(
143 name='repo_file_download',
143 name='repo_file_download',
144 pattern='/{repo_name:.*?[^/]}/download/{commit_id}/{f_path:.*}', repo_route=True)
144 pattern='/{repo_name:.*?[^/]}/download/{commit_id}/{f_path:.*}', repo_route=True)
145 config.add_route( # backward compat to keep old links working
145 config.add_route( # backward compat to keep old links working
146 name='repo_file_download:legacy',
146 name='repo_file_download:legacy',
147 pattern='/{repo_name:.*?[^/]}/rawfile/{commit_id}/{f_path:.*}',
147 pattern='/{repo_name:.*?[^/]}/rawfile/{commit_id}/{f_path:.*}',
148 repo_route=True)
148 repo_route=True)
149
149
150 config.add_route(
150 config.add_route(
151 name='repo_file_history',
151 name='repo_file_history',
152 pattern='/{repo_name:.*?[^/]}/history/{commit_id}/{f_path:.*}', repo_route=True)
152 pattern='/{repo_name:.*?[^/]}/history/{commit_id}/{f_path:.*}', repo_route=True)
153
153
154 config.add_route(
154 config.add_route(
155 name='repo_file_authors',
155 name='repo_file_authors',
156 pattern='/{repo_name:.*?[^/]}/authors/{commit_id}/{f_path:.*}', repo_route=True)
156 pattern='/{repo_name:.*?[^/]}/authors/{commit_id}/{f_path:.*}', repo_route=True)
157
157
158 config.add_route(
158 config.add_route(
159 name='repo_files_check_head',
160 pattern='/{repo_name:.*?[^/]}/check_head/{commit_id}/{f_path:.*}',
161 repo_route=True)
162 config.add_route(
159 name='repo_files_remove_file',
163 name='repo_files_remove_file',
160 pattern='/{repo_name:.*?[^/]}/remove_file/{commit_id}/{f_path:.*}',
164 pattern='/{repo_name:.*?[^/]}/remove_file/{commit_id}/{f_path:.*}',
161 repo_route=True)
165 repo_route=True)
162 config.add_route(
166 config.add_route(
163 name='repo_files_delete_file',
167 name='repo_files_delete_file',
164 pattern='/{repo_name:.*?[^/]}/delete_file/{commit_id}/{f_path:.*}',
168 pattern='/{repo_name:.*?[^/]}/delete_file/{commit_id}/{f_path:.*}',
165 repo_route=True)
169 repo_route=True)
166 config.add_route(
170 config.add_route(
167 name='repo_files_edit_file',
171 name='repo_files_edit_file',
168 pattern='/{repo_name:.*?[^/]}/edit_file/{commit_id}/{f_path:.*}',
172 pattern='/{repo_name:.*?[^/]}/edit_file/{commit_id}/{f_path:.*}',
169 repo_route=True)
173 repo_route=True)
170 config.add_route(
174 config.add_route(
171 name='repo_files_update_file',
175 name='repo_files_update_file',
172 pattern='/{repo_name:.*?[^/]}/update_file/{commit_id}/{f_path:.*}',
176 pattern='/{repo_name:.*?[^/]}/update_file/{commit_id}/{f_path:.*}',
173 repo_route=True)
177 repo_route=True)
174 config.add_route(
178 config.add_route(
175 name='repo_files_add_file',
179 name='repo_files_add_file',
176 pattern='/{repo_name:.*?[^/]}/add_file/{commit_id}/{f_path:.*}',
180 pattern='/{repo_name:.*?[^/]}/add_file/{commit_id}/{f_path:.*}',
177 repo_route=True)
181 repo_route=True)
178 config.add_route(
182 config.add_route(
179 name='repo_files_upload_file',
183 name='repo_files_upload_file',
180 pattern='/{repo_name:.*?[^/]}/upload_file/{commit_id}/{f_path:.*}',
184 pattern='/{repo_name:.*?[^/]}/upload_file/{commit_id}/{f_path:.*}',
181 repo_route=True)
185 repo_route=True)
182 config.add_route(
186 config.add_route(
183 name='repo_files_create_file',
187 name='repo_files_create_file',
184 pattern='/{repo_name:.*?[^/]}/create_file/{commit_id}/{f_path:.*}',
188 pattern='/{repo_name:.*?[^/]}/create_file/{commit_id}/{f_path:.*}',
185 repo_route=True)
189 repo_route=True)
186
190
187 # Refs data
191 # Refs data
188 config.add_route(
192 config.add_route(
189 name='repo_refs_data',
193 name='repo_refs_data',
190 pattern='/{repo_name:.*?[^/]}/refs-data', repo_route=True)
194 pattern='/{repo_name:.*?[^/]}/refs-data', repo_route=True)
191
195
192 config.add_route(
196 config.add_route(
193 name='repo_refs_changelog_data',
197 name='repo_refs_changelog_data',
194 pattern='/{repo_name:.*?[^/]}/refs-data-changelog', repo_route=True)
198 pattern='/{repo_name:.*?[^/]}/refs-data-changelog', repo_route=True)
195
199
196 config.add_route(
200 config.add_route(
197 name='repo_stats',
201 name='repo_stats',
198 pattern='/{repo_name:.*?[^/]}/repo_stats/{commit_id}', repo_route=True)
202 pattern='/{repo_name:.*?[^/]}/repo_stats/{commit_id}', repo_route=True)
199
203
200 # Commits
204 # Commits
201 config.add_route(
205 config.add_route(
202 name='repo_commits',
206 name='repo_commits',
203 pattern='/{repo_name:.*?[^/]}/commits', repo_route=True)
207 pattern='/{repo_name:.*?[^/]}/commits', repo_route=True)
204 config.add_route(
208 config.add_route(
205 name='repo_commits_file',
209 name='repo_commits_file',
206 pattern='/{repo_name:.*?[^/]}/commits/{commit_id}/{f_path:.*}', repo_route=True)
210 pattern='/{repo_name:.*?[^/]}/commits/{commit_id}/{f_path:.*}', repo_route=True)
207 config.add_route(
211 config.add_route(
208 name='repo_commits_elements',
212 name='repo_commits_elements',
209 pattern='/{repo_name:.*?[^/]}/commits_elements', repo_route=True)
213 pattern='/{repo_name:.*?[^/]}/commits_elements', repo_route=True)
210 config.add_route(
214 config.add_route(
211 name='repo_commits_elements_file',
215 name='repo_commits_elements_file',
212 pattern='/{repo_name:.*?[^/]}/commits_elements/{commit_id}/{f_path:.*}', repo_route=True)
216 pattern='/{repo_name:.*?[^/]}/commits_elements/{commit_id}/{f_path:.*}', repo_route=True)
213
217
214 # Changelog (old deprecated name for commits page)
218 # Changelog (old deprecated name for commits page)
215 config.add_route(
219 config.add_route(
216 name='repo_changelog',
220 name='repo_changelog',
217 pattern='/{repo_name:.*?[^/]}/changelog', repo_route=True)
221 pattern='/{repo_name:.*?[^/]}/changelog', repo_route=True)
218 config.add_route(
222 config.add_route(
219 name='repo_changelog_file',
223 name='repo_changelog_file',
220 pattern='/{repo_name:.*?[^/]}/changelog/{commit_id}/{f_path:.*}', repo_route=True)
224 pattern='/{repo_name:.*?[^/]}/changelog/{commit_id}/{f_path:.*}', repo_route=True)
221
225
222 # Compare
226 # Compare
223 config.add_route(
227 config.add_route(
224 name='repo_compare_select',
228 name='repo_compare_select',
225 pattern='/{repo_name:.*?[^/]}/compare', repo_route=True)
229 pattern='/{repo_name:.*?[^/]}/compare', repo_route=True)
226
230
227 config.add_route(
231 config.add_route(
228 name='repo_compare',
232 name='repo_compare',
229 pattern='/{repo_name:.*?[^/]}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}', repo_route=True)
233 pattern='/{repo_name:.*?[^/]}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}', repo_route=True)
230
234
231 # Tags
235 # Tags
232 config.add_route(
236 config.add_route(
233 name='tags_home',
237 name='tags_home',
234 pattern='/{repo_name:.*?[^/]}/tags', repo_route=True)
238 pattern='/{repo_name:.*?[^/]}/tags', repo_route=True)
235
239
236 # Branches
240 # Branches
237 config.add_route(
241 config.add_route(
238 name='branches_home',
242 name='branches_home',
239 pattern='/{repo_name:.*?[^/]}/branches', repo_route=True)
243 pattern='/{repo_name:.*?[^/]}/branches', repo_route=True)
240
244
241 # Bookmarks
245 # Bookmarks
242 config.add_route(
246 config.add_route(
243 name='bookmarks_home',
247 name='bookmarks_home',
244 pattern='/{repo_name:.*?[^/]}/bookmarks', repo_route=True)
248 pattern='/{repo_name:.*?[^/]}/bookmarks', repo_route=True)
245
249
246 # Forks
250 # Forks
247 config.add_route(
251 config.add_route(
248 name='repo_fork_new',
252 name='repo_fork_new',
249 pattern='/{repo_name:.*?[^/]}/fork', repo_route=True,
253 pattern='/{repo_name:.*?[^/]}/fork', repo_route=True,
250 repo_forbid_when_archived=True,
254 repo_forbid_when_archived=True,
251 repo_accepted_types=['hg', 'git'])
255 repo_accepted_types=['hg', 'git'])
252
256
253 config.add_route(
257 config.add_route(
254 name='repo_fork_create',
258 name='repo_fork_create',
255 pattern='/{repo_name:.*?[^/]}/fork/create', repo_route=True,
259 pattern='/{repo_name:.*?[^/]}/fork/create', repo_route=True,
256 repo_forbid_when_archived=True,
260 repo_forbid_when_archived=True,
257 repo_accepted_types=['hg', 'git'])
261 repo_accepted_types=['hg', 'git'])
258
262
259 config.add_route(
263 config.add_route(
260 name='repo_forks_show_all',
264 name='repo_forks_show_all',
261 pattern='/{repo_name:.*?[^/]}/forks', repo_route=True,
265 pattern='/{repo_name:.*?[^/]}/forks', repo_route=True,
262 repo_accepted_types=['hg', 'git'])
266 repo_accepted_types=['hg', 'git'])
263 config.add_route(
267 config.add_route(
264 name='repo_forks_data',
268 name='repo_forks_data',
265 pattern='/{repo_name:.*?[^/]}/forks/data', repo_route=True,
269 pattern='/{repo_name:.*?[^/]}/forks/data', repo_route=True,
266 repo_accepted_types=['hg', 'git'])
270 repo_accepted_types=['hg', 'git'])
267
271
268 # Pull Requests
272 # Pull Requests
269 config.add_route(
273 config.add_route(
270 name='pullrequest_show',
274 name='pullrequest_show',
271 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}',
275 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}',
272 repo_route=True)
276 repo_route=True)
273
277
274 config.add_route(
278 config.add_route(
275 name='pullrequest_show_all',
279 name='pullrequest_show_all',
276 pattern='/{repo_name:.*?[^/]}/pull-request',
280 pattern='/{repo_name:.*?[^/]}/pull-request',
277 repo_route=True, repo_accepted_types=['hg', 'git'])
281 repo_route=True, repo_accepted_types=['hg', 'git'])
278
282
279 config.add_route(
283 config.add_route(
280 name='pullrequest_show_all_data',
284 name='pullrequest_show_all_data',
281 pattern='/{repo_name:.*?[^/]}/pull-request-data',
285 pattern='/{repo_name:.*?[^/]}/pull-request-data',
282 repo_route=True, repo_accepted_types=['hg', 'git'])
286 repo_route=True, repo_accepted_types=['hg', 'git'])
283
287
284 config.add_route(
288 config.add_route(
285 name='pullrequest_repo_refs',
289 name='pullrequest_repo_refs',
286 pattern='/{repo_name:.*?[^/]}/pull-request/refs/{target_repo_name:.*?[^/]}',
290 pattern='/{repo_name:.*?[^/]}/pull-request/refs/{target_repo_name:.*?[^/]}',
287 repo_route=True)
291 repo_route=True)
288
292
289 config.add_route(
293 config.add_route(
290 name='pullrequest_repo_targets',
294 name='pullrequest_repo_targets',
291 pattern='/{repo_name:.*?[^/]}/pull-request/repo-targets',
295 pattern='/{repo_name:.*?[^/]}/pull-request/repo-targets',
292 repo_route=True)
296 repo_route=True)
293
297
294 config.add_route(
298 config.add_route(
295 name='pullrequest_new',
299 name='pullrequest_new',
296 pattern='/{repo_name:.*?[^/]}/pull-request/new',
300 pattern='/{repo_name:.*?[^/]}/pull-request/new',
297 repo_route=True, repo_accepted_types=['hg', 'git'],
301 repo_route=True, repo_accepted_types=['hg', 'git'],
298 repo_forbid_when_archived=True)
302 repo_forbid_when_archived=True)
299
303
300 config.add_route(
304 config.add_route(
301 name='pullrequest_create',
305 name='pullrequest_create',
302 pattern='/{repo_name:.*?[^/]}/pull-request/create',
306 pattern='/{repo_name:.*?[^/]}/pull-request/create',
303 repo_route=True, repo_accepted_types=['hg', 'git'],
307 repo_route=True, repo_accepted_types=['hg', 'git'],
304 repo_forbid_when_archived=True)
308 repo_forbid_when_archived=True)
305
309
306 config.add_route(
310 config.add_route(
307 name='pullrequest_update',
311 name='pullrequest_update',
308 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/update',
312 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/update',
309 repo_route=True, repo_forbid_when_archived=True)
313 repo_route=True, repo_forbid_when_archived=True)
310
314
311 config.add_route(
315 config.add_route(
312 name='pullrequest_merge',
316 name='pullrequest_merge',
313 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/merge',
317 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/merge',
314 repo_route=True, repo_forbid_when_archived=True)
318 repo_route=True, repo_forbid_when_archived=True)
315
319
316 config.add_route(
320 config.add_route(
317 name='pullrequest_delete',
321 name='pullrequest_delete',
318 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/delete',
322 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/delete',
319 repo_route=True, repo_forbid_when_archived=True)
323 repo_route=True, repo_forbid_when_archived=True)
320
324
321 config.add_route(
325 config.add_route(
322 name='pullrequest_comment_create',
326 name='pullrequest_comment_create',
323 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment',
327 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment',
324 repo_route=True)
328 repo_route=True)
325
329
326 config.add_route(
330 config.add_route(
327 name='pullrequest_comment_delete',
331 name='pullrequest_comment_delete',
328 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment/{comment_id}/delete',
332 pattern='/{repo_name:.*?[^/]}/pull-request/{pull_request_id:\d+}/comment/{comment_id}/delete',
329 repo_route=True, repo_accepted_types=['hg', 'git'])
333 repo_route=True, repo_accepted_types=['hg', 'git'])
330
334
331 # Artifacts, (EE feature)
335 # Artifacts, (EE feature)
332 config.add_route(
336 config.add_route(
333 name='repo_artifacts_list',
337 name='repo_artifacts_list',
334 pattern='/{repo_name:.*?[^/]}/artifacts', repo_route=True)
338 pattern='/{repo_name:.*?[^/]}/artifacts', repo_route=True)
335
339
336 # Settings
340 # Settings
337 config.add_route(
341 config.add_route(
338 name='edit_repo',
342 name='edit_repo',
339 pattern='/{repo_name:.*?[^/]}/settings', repo_route=True)
343 pattern='/{repo_name:.*?[^/]}/settings', repo_route=True)
340 # update is POST on edit_repo
344 # update is POST on edit_repo
341
345
342 # Settings advanced
346 # Settings advanced
343 config.add_route(
347 config.add_route(
344 name='edit_repo_advanced',
348 name='edit_repo_advanced',
345 pattern='/{repo_name:.*?[^/]}/settings/advanced', repo_route=True)
349 pattern='/{repo_name:.*?[^/]}/settings/advanced', repo_route=True)
346 config.add_route(
350 config.add_route(
347 name='edit_repo_advanced_archive',
351 name='edit_repo_advanced_archive',
348 pattern='/{repo_name:.*?[^/]}/settings/advanced/archive', repo_route=True)
352 pattern='/{repo_name:.*?[^/]}/settings/advanced/archive', repo_route=True)
349 config.add_route(
353 config.add_route(
350 name='edit_repo_advanced_delete',
354 name='edit_repo_advanced_delete',
351 pattern='/{repo_name:.*?[^/]}/settings/advanced/delete', repo_route=True)
355 pattern='/{repo_name:.*?[^/]}/settings/advanced/delete', repo_route=True)
352 config.add_route(
356 config.add_route(
353 name='edit_repo_advanced_locking',
357 name='edit_repo_advanced_locking',
354 pattern='/{repo_name:.*?[^/]}/settings/advanced/locking', repo_route=True)
358 pattern='/{repo_name:.*?[^/]}/settings/advanced/locking', repo_route=True)
355 config.add_route(
359 config.add_route(
356 name='edit_repo_advanced_journal',
360 name='edit_repo_advanced_journal',
357 pattern='/{repo_name:.*?[^/]}/settings/advanced/journal', repo_route=True)
361 pattern='/{repo_name:.*?[^/]}/settings/advanced/journal', repo_route=True)
358 config.add_route(
362 config.add_route(
359 name='edit_repo_advanced_fork',
363 name='edit_repo_advanced_fork',
360 pattern='/{repo_name:.*?[^/]}/settings/advanced/fork', repo_route=True)
364 pattern='/{repo_name:.*?[^/]}/settings/advanced/fork', repo_route=True)
361
365
362 config.add_route(
366 config.add_route(
363 name='edit_repo_advanced_hooks',
367 name='edit_repo_advanced_hooks',
364 pattern='/{repo_name:.*?[^/]}/settings/advanced/hooks', repo_route=True)
368 pattern='/{repo_name:.*?[^/]}/settings/advanced/hooks', repo_route=True)
365
369
366 # Caches
370 # Caches
367 config.add_route(
371 config.add_route(
368 name='edit_repo_caches',
372 name='edit_repo_caches',
369 pattern='/{repo_name:.*?[^/]}/settings/caches', repo_route=True)
373 pattern='/{repo_name:.*?[^/]}/settings/caches', repo_route=True)
370
374
371 # Permissions
375 # Permissions
372 config.add_route(
376 config.add_route(
373 name='edit_repo_perms',
377 name='edit_repo_perms',
374 pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True)
378 pattern='/{repo_name:.*?[^/]}/settings/permissions', repo_route=True)
375
379
376 config.add_route(
380 config.add_route(
377 name='edit_repo_perms_set_private',
381 name='edit_repo_perms_set_private',
378 pattern='/{repo_name:.*?[^/]}/settings/permissions/set_private', repo_route=True)
382 pattern='/{repo_name:.*?[^/]}/settings/permissions/set_private', repo_route=True)
379
383
380 # Permissions Branch (EE feature)
384 # Permissions Branch (EE feature)
381 config.add_route(
385 config.add_route(
382 name='edit_repo_perms_branch',
386 name='edit_repo_perms_branch',
383 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions', repo_route=True)
387 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions', repo_route=True)
384 config.add_route(
388 config.add_route(
385 name='edit_repo_perms_branch_delete',
389 name='edit_repo_perms_branch_delete',
386 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions/{rule_id}/delete',
390 pattern='/{repo_name:.*?[^/]}/settings/branch_permissions/{rule_id}/delete',
387 repo_route=True)
391 repo_route=True)
388
392
389 # Maintenance
393 # Maintenance
390 config.add_route(
394 config.add_route(
391 name='edit_repo_maintenance',
395 name='edit_repo_maintenance',
392 pattern='/{repo_name:.*?[^/]}/settings/maintenance', repo_route=True)
396 pattern='/{repo_name:.*?[^/]}/settings/maintenance', repo_route=True)
393
397
394 config.add_route(
398 config.add_route(
395 name='edit_repo_maintenance_execute',
399 name='edit_repo_maintenance_execute',
396 pattern='/{repo_name:.*?[^/]}/settings/maintenance/execute', repo_route=True)
400 pattern='/{repo_name:.*?[^/]}/settings/maintenance/execute', repo_route=True)
397
401
398 # Fields
402 # Fields
399 config.add_route(
403 config.add_route(
400 name='edit_repo_fields',
404 name='edit_repo_fields',
401 pattern='/{repo_name:.*?[^/]}/settings/fields', repo_route=True)
405 pattern='/{repo_name:.*?[^/]}/settings/fields', repo_route=True)
402 config.add_route(
406 config.add_route(
403 name='edit_repo_fields_create',
407 name='edit_repo_fields_create',
404 pattern='/{repo_name:.*?[^/]}/settings/fields/create', repo_route=True)
408 pattern='/{repo_name:.*?[^/]}/settings/fields/create', repo_route=True)
405 config.add_route(
409 config.add_route(
406 name='edit_repo_fields_delete',
410 name='edit_repo_fields_delete',
407 pattern='/{repo_name:.*?[^/]}/settings/fields/{field_id}/delete', repo_route=True)
411 pattern='/{repo_name:.*?[^/]}/settings/fields/{field_id}/delete', repo_route=True)
408
412
409 # Locking
413 # Locking
410 config.add_route(
414 config.add_route(
411 name='repo_edit_toggle_locking',
415 name='repo_edit_toggle_locking',
412 pattern='/{repo_name:.*?[^/]}/settings/toggle_locking', repo_route=True)
416 pattern='/{repo_name:.*?[^/]}/settings/toggle_locking', repo_route=True)
413
417
414 # Remote
418 # Remote
415 config.add_route(
419 config.add_route(
416 name='edit_repo_remote',
420 name='edit_repo_remote',
417 pattern='/{repo_name:.*?[^/]}/settings/remote', repo_route=True)
421 pattern='/{repo_name:.*?[^/]}/settings/remote', repo_route=True)
418 config.add_route(
422 config.add_route(
419 name='edit_repo_remote_pull',
423 name='edit_repo_remote_pull',
420 pattern='/{repo_name:.*?[^/]}/settings/remote/pull', repo_route=True)
424 pattern='/{repo_name:.*?[^/]}/settings/remote/pull', repo_route=True)
421 config.add_route(
425 config.add_route(
422 name='edit_repo_remote_push',
426 name='edit_repo_remote_push',
423 pattern='/{repo_name:.*?[^/]}/settings/remote/push', repo_route=True)
427 pattern='/{repo_name:.*?[^/]}/settings/remote/push', repo_route=True)
424
428
425 # Statistics
429 # Statistics
426 config.add_route(
430 config.add_route(
427 name='edit_repo_statistics',
431 name='edit_repo_statistics',
428 pattern='/{repo_name:.*?[^/]}/settings/statistics', repo_route=True)
432 pattern='/{repo_name:.*?[^/]}/settings/statistics', repo_route=True)
429 config.add_route(
433 config.add_route(
430 name='edit_repo_statistics_reset',
434 name='edit_repo_statistics_reset',
431 pattern='/{repo_name:.*?[^/]}/settings/statistics/update', repo_route=True)
435 pattern='/{repo_name:.*?[^/]}/settings/statistics/update', repo_route=True)
432
436
433 # Issue trackers
437 # Issue trackers
434 config.add_route(
438 config.add_route(
435 name='edit_repo_issuetracker',
439 name='edit_repo_issuetracker',
436 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers', repo_route=True)
440 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers', repo_route=True)
437 config.add_route(
441 config.add_route(
438 name='edit_repo_issuetracker_test',
442 name='edit_repo_issuetracker_test',
439 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/test', repo_route=True)
443 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/test', repo_route=True)
440 config.add_route(
444 config.add_route(
441 name='edit_repo_issuetracker_delete',
445 name='edit_repo_issuetracker_delete',
442 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/delete', repo_route=True)
446 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/delete', repo_route=True)
443 config.add_route(
447 config.add_route(
444 name='edit_repo_issuetracker_update',
448 name='edit_repo_issuetracker_update',
445 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/update', repo_route=True)
449 pattern='/{repo_name:.*?[^/]}/settings/issue_trackers/update', repo_route=True)
446
450
447 # VCS Settings
451 # VCS Settings
448 config.add_route(
452 config.add_route(
449 name='edit_repo_vcs',
453 name='edit_repo_vcs',
450 pattern='/{repo_name:.*?[^/]}/settings/vcs', repo_route=True)
454 pattern='/{repo_name:.*?[^/]}/settings/vcs', repo_route=True)
451 config.add_route(
455 config.add_route(
452 name='edit_repo_vcs_update',
456 name='edit_repo_vcs_update',
453 pattern='/{repo_name:.*?[^/]}/settings/vcs/update', repo_route=True)
457 pattern='/{repo_name:.*?[^/]}/settings/vcs/update', repo_route=True)
454
458
455 # svn pattern
459 # svn pattern
456 config.add_route(
460 config.add_route(
457 name='edit_repo_vcs_svn_pattern_delete',
461 name='edit_repo_vcs_svn_pattern_delete',
458 pattern='/{repo_name:.*?[^/]}/settings/vcs/svn_pattern/delete', repo_route=True)
462 pattern='/{repo_name:.*?[^/]}/settings/vcs/svn_pattern/delete', repo_route=True)
459
463
460 # Repo Review Rules (EE feature)
464 # Repo Review Rules (EE feature)
461 config.add_route(
465 config.add_route(
462 name='repo_reviewers',
466 name='repo_reviewers',
463 pattern='/{repo_name:.*?[^/]}/settings/review/rules', repo_route=True)
467 pattern='/{repo_name:.*?[^/]}/settings/review/rules', repo_route=True)
464
468
465 config.add_route(
469 config.add_route(
466 name='repo_default_reviewers_data',
470 name='repo_default_reviewers_data',
467 pattern='/{repo_name:.*?[^/]}/settings/review/default-reviewers', repo_route=True)
471 pattern='/{repo_name:.*?[^/]}/settings/review/default-reviewers', repo_route=True)
468
472
469 # Repo Automation (EE feature)
473 # Repo Automation (EE feature)
470 config.add_route(
474 config.add_route(
471 name='repo_automation',
475 name='repo_automation',
472 pattern='/{repo_name:.*?[^/]}/settings/automation', repo_route=True)
476 pattern='/{repo_name:.*?[^/]}/settings/automation', repo_route=True)
473
477
474 # Strip
478 # Strip
475 config.add_route(
479 config.add_route(
476 name='edit_repo_strip',
480 name='edit_repo_strip',
477 pattern='/{repo_name:.*?[^/]}/settings/strip', repo_route=True)
481 pattern='/{repo_name:.*?[^/]}/settings/strip', repo_route=True)
478
482
479 config.add_route(
483 config.add_route(
480 name='strip_check',
484 name='strip_check',
481 pattern='/{repo_name:.*?[^/]}/settings/strip_check', repo_route=True)
485 pattern='/{repo_name:.*?[^/]}/settings/strip_check', repo_route=True)
482
486
483 config.add_route(
487 config.add_route(
484 name='strip_execute',
488 name='strip_execute',
485 pattern='/{repo_name:.*?[^/]}/settings/strip_execute', repo_route=True)
489 pattern='/{repo_name:.*?[^/]}/settings/strip_execute', repo_route=True)
486
490
487 # Audit logs
491 # Audit logs
488 config.add_route(
492 config.add_route(
489 name='edit_repo_audit_logs',
493 name='edit_repo_audit_logs',
490 pattern='/{repo_name:.*?[^/]}/settings/audit_logs', repo_route=True)
494 pattern='/{repo_name:.*?[^/]}/settings/audit_logs', repo_route=True)
491
495
492 # ATOM/RSS Feed, shouldn't contain slashes for outlook compatibility
496 # ATOM/RSS Feed, shouldn't contain slashes for outlook compatibility
493 config.add_route(
497 config.add_route(
494 name='rss_feed_home',
498 name='rss_feed_home',
495 pattern='/{repo_name:.*?[^/]}/feed-rss', repo_route=True)
499 pattern='/{repo_name:.*?[^/]}/feed-rss', repo_route=True)
496
500
497 config.add_route(
501 config.add_route(
498 name='atom_feed_home',
502 name='atom_feed_home',
499 pattern='/{repo_name:.*?[^/]}/feed-atom', repo_route=True)
503 pattern='/{repo_name:.*?[^/]}/feed-atom', repo_route=True)
500
504
501 config.add_route(
505 config.add_route(
502 name='rss_feed_home_old',
506 name='rss_feed_home_old',
503 pattern='/{repo_name:.*?[^/]}/feed/rss', repo_route=True)
507 pattern='/{repo_name:.*?[^/]}/feed/rss', repo_route=True)
504
508
505 config.add_route(
509 config.add_route(
506 name='atom_feed_home_old',
510 name='atom_feed_home_old',
507 pattern='/{repo_name:.*?[^/]}/feed/atom', repo_route=True)
511 pattern='/{repo_name:.*?[^/]}/feed/atom', repo_route=True)
508
512
509 # NOTE(marcink): needs to be at the end for catch-all
513 # NOTE(marcink): needs to be at the end for catch-all
510 add_route_with_slash(
514 add_route_with_slash(
511 config,
515 config,
512 name='repo_summary',
516 name='repo_summary',
513 pattern='/{repo_name:.*?[^/]}', repo_route=True)
517 pattern='/{repo_name:.*?[^/]}', repo_route=True)
514
518
515 # Scan module for configuration decorators.
519 # Scan module for configuration decorators.
516 config.scan('.views', ignore='.tests')
520 config.scan('.views', ignore='.tests')
@@ -1,1568 +1,1604 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 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 import itertools
21 import itertools
22 import logging
22 import logging
23 import os
23 import os
24 import shutil
24 import shutil
25 import tempfile
25 import tempfile
26 import collections
26 import collections
27 import urllib
27 import urllib
28 import pathlib2
28 import pathlib2
29
29
30 from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound
30 from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound
31 from pyramid.view import view_config
31 from pyramid.view import view_config
32 from pyramid.renderers import render
32 from pyramid.renderers import render
33 from pyramid.response import Response
33 from pyramid.response import Response
34
34
35 import rhodecode
35 import rhodecode
36 from rhodecode.apps._base import RepoAppView
36 from rhodecode.apps._base import RepoAppView
37
37
38
38
39 from rhodecode.lib import diffs, helpers as h, rc_cache
39 from rhodecode.lib import diffs, helpers as h, rc_cache
40 from rhodecode.lib import audit_logger
40 from rhodecode.lib import audit_logger
41 from rhodecode.lib.view_utils import parse_path_ref
41 from rhodecode.lib.view_utils import parse_path_ref
42 from rhodecode.lib.exceptions import NonRelativePathError
42 from rhodecode.lib.exceptions import NonRelativePathError
43 from rhodecode.lib.codeblocks import (
43 from rhodecode.lib.codeblocks import (
44 filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
44 filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
45 from rhodecode.lib.utils2 import (
45 from rhodecode.lib.utils2 import (
46 convert_line_endings, detect_mode, safe_str, str2bool, safe_int, sha1, safe_unicode)
46 convert_line_endings, detect_mode, safe_str, str2bool, safe_int, sha1, safe_unicode)
47 from rhodecode.lib.auth import (
47 from rhodecode.lib.auth import (
48 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
48 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
49 from rhodecode.lib.vcs import path as vcspath
49 from rhodecode.lib.vcs import path as vcspath
50 from rhodecode.lib.vcs.backends.base import EmptyCommit
50 from rhodecode.lib.vcs.backends.base import EmptyCommit
51 from rhodecode.lib.vcs.conf import settings
51 from rhodecode.lib.vcs.conf import settings
52 from rhodecode.lib.vcs.nodes import FileNode
52 from rhodecode.lib.vcs.nodes import FileNode
53 from rhodecode.lib.vcs.exceptions import (
53 from rhodecode.lib.vcs.exceptions import (
54 RepositoryError, CommitDoesNotExistError, EmptyRepositoryError,
54 RepositoryError, CommitDoesNotExistError, EmptyRepositoryError,
55 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,
55 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,
56 NodeDoesNotExistError, CommitError, NodeError)
56 NodeDoesNotExistError, CommitError, NodeError)
57
57
58 from rhodecode.model.scm import ScmModel
58 from rhodecode.model.scm import ScmModel
59 from rhodecode.model.db import Repository
59 from rhodecode.model.db import Repository
60
60
61 log = logging.getLogger(__name__)
61 log = logging.getLogger(__name__)
62
62
63
63
64 class RepoFilesView(RepoAppView):
64 class RepoFilesView(RepoAppView):
65
65
66 @staticmethod
66 @staticmethod
67 def adjust_file_path_for_svn(f_path, repo):
67 def adjust_file_path_for_svn(f_path, repo):
68 """
68 """
69 Computes the relative path of `f_path`.
69 Computes the relative path of `f_path`.
70
70
71 This is mainly based on prefix matching of the recognized tags and
71 This is mainly based on prefix matching of the recognized tags and
72 branches in the underlying repository.
72 branches in the underlying repository.
73 """
73 """
74 tags_and_branches = itertools.chain(
74 tags_and_branches = itertools.chain(
75 repo.branches.iterkeys(),
75 repo.branches.iterkeys(),
76 repo.tags.iterkeys())
76 repo.tags.iterkeys())
77 tags_and_branches = sorted(tags_and_branches, key=len, reverse=True)
77 tags_and_branches = sorted(tags_and_branches, key=len, reverse=True)
78
78
79 for name in tags_and_branches:
79 for name in tags_and_branches:
80 if f_path.startswith('{}/'.format(name)):
80 if f_path.startswith('{}/'.format(name)):
81 f_path = vcspath.relpath(f_path, name)
81 f_path = vcspath.relpath(f_path, name)
82 break
82 break
83 return f_path
83 return f_path
84
84
85 def load_default_context(self):
85 def load_default_context(self):
86 c = self._get_local_tmpl_context(include_app_defaults=True)
86 c = self._get_local_tmpl_context(include_app_defaults=True)
87 c.rhodecode_repo = self.rhodecode_vcs_repo
87 c.rhodecode_repo = self.rhodecode_vcs_repo
88 c.enable_downloads = self.db_repo.enable_downloads
88 c.enable_downloads = self.db_repo.enable_downloads
89 return c
89 return c
90
90
91 def _ensure_not_locked(self, commit_id='tip'):
91 def _ensure_not_locked(self, commit_id='tip'):
92 _ = self.request.translate
92 _ = self.request.translate
93
93
94 repo = self.db_repo
94 repo = self.db_repo
95 if repo.enable_locking and repo.locked[0]:
95 if repo.enable_locking and repo.locked[0]:
96 h.flash(_('This repository has been locked by %s on %s')
96 h.flash(_('This repository has been locked by %s on %s')
97 % (h.person_by_id(repo.locked[0]),
97 % (h.person_by_id(repo.locked[0]),
98 h.format_date(h.time_to_datetime(repo.locked[1]))),
98 h.format_date(h.time_to_datetime(repo.locked[1]))),
99 'warning')
99 'warning')
100 files_url = h.route_path(
100 files_url = h.route_path(
101 'repo_files:default_path',
101 'repo_files:default_path',
102 repo_name=self.db_repo_name, commit_id=commit_id)
102 repo_name=self.db_repo_name, commit_id=commit_id)
103 raise HTTPFound(files_url)
103 raise HTTPFound(files_url)
104
104
105 def forbid_non_head(self, is_head, f_path, commit_id='tip', json_mode=False):
105 def forbid_non_head(self, is_head, f_path, commit_id='tip', json_mode=False):
106 _ = self.request.translate
106 _ = self.request.translate
107
107
108 if not is_head:
108 if not is_head:
109 message = _('Cannot modify file. '
109 message = _('Cannot modify file. '
110 'Given commit `{}` is not head of a branch.').format(commit_id)
110 'Given commit `{}` is not head of a branch.').format(commit_id)
111 h.flash(message, category='warning')
111 h.flash(message, category='warning')
112
112
113 if json_mode:
113 if json_mode:
114 return message
114 return message
115
115
116 files_url = h.route_path(
116 files_url = h.route_path(
117 'repo_files', repo_name=self.db_repo_name, commit_id=commit_id,
117 'repo_files', repo_name=self.db_repo_name, commit_id=commit_id,
118 f_path=f_path)
118 f_path=f_path)
119 raise HTTPFound(files_url)
119 raise HTTPFound(files_url)
120
120
121 def check_branch_permission(self, branch_name, commit_id='tip', json_mode=False):
121 def check_branch_permission(self, branch_name, commit_id='tip', json_mode=False):
122 _ = self.request.translate
122 _ = self.request.translate
123
123
124 rule, branch_perm = self._rhodecode_user.get_rule_and_branch_permission(
124 rule, branch_perm = self._rhodecode_user.get_rule_and_branch_permission(
125 self.db_repo_name, branch_name)
125 self.db_repo_name, branch_name)
126 if branch_perm and branch_perm not in ['branch.push', 'branch.push_force']:
126 if branch_perm and branch_perm not in ['branch.push', 'branch.push_force']:
127 message = _('Branch `{}` changes forbidden by rule {}.').format(
127 message = _('Branch `{}` changes forbidden by rule {}.').format(
128 branch_name, rule)
128 branch_name, rule)
129 h.flash(message, 'warning')
129 h.flash(message, 'warning')
130
130
131 if json_mode:
131 if json_mode:
132 return message
132 return message
133
133
134 files_url = h.route_path(
134 files_url = h.route_path(
135 'repo_files:default_path', repo_name=self.db_repo_name, commit_id=commit_id)
135 'repo_files:default_path', repo_name=self.db_repo_name, commit_id=commit_id)
136
136
137 raise HTTPFound(files_url)
137 raise HTTPFound(files_url)
138
138
139 def _get_commit_and_path(self):
139 def _get_commit_and_path(self):
140 default_commit_id = self.db_repo.landing_rev[1]
140 default_commit_id = self.db_repo.landing_rev[1]
141 default_f_path = '/'
141 default_f_path = '/'
142
142
143 commit_id = self.request.matchdict.get(
143 commit_id = self.request.matchdict.get(
144 'commit_id', default_commit_id)
144 'commit_id', default_commit_id)
145 f_path = self._get_f_path(self.request.matchdict, default_f_path)
145 f_path = self._get_f_path(self.request.matchdict, default_f_path)
146 return commit_id, f_path
146 return commit_id, f_path
147
147
148 def _get_default_encoding(self, c):
148 def _get_default_encoding(self, c):
149 enc_list = getattr(c, 'default_encodings', [])
149 enc_list = getattr(c, 'default_encodings', [])
150 return enc_list[0] if enc_list else 'UTF-8'
150 return enc_list[0] if enc_list else 'UTF-8'
151
151
152 def _get_commit_or_redirect(self, commit_id, redirect_after=True):
152 def _get_commit_or_redirect(self, commit_id, redirect_after=True):
153 """
153 """
154 This is a safe way to get commit. If an error occurs it redirects to
154 This is a safe way to get commit. If an error occurs it redirects to
155 tip with proper message
155 tip with proper message
156
156
157 :param commit_id: id of commit to fetch
157 :param commit_id: id of commit to fetch
158 :param redirect_after: toggle redirection
158 :param redirect_after: toggle redirection
159 """
159 """
160 _ = self.request.translate
160 _ = self.request.translate
161
161
162 try:
162 try:
163 return self.rhodecode_vcs_repo.get_commit(commit_id)
163 return self.rhodecode_vcs_repo.get_commit(commit_id)
164 except EmptyRepositoryError:
164 except EmptyRepositoryError:
165 if not redirect_after:
165 if not redirect_after:
166 return None
166 return None
167
167
168 _url = h.route_path(
168 _url = h.route_path(
169 'repo_files_add_file',
169 'repo_files_add_file',
170 repo_name=self.db_repo_name, commit_id=0, f_path='')
170 repo_name=self.db_repo_name, commit_id=0, f_path='')
171
171
172 if h.HasRepoPermissionAny(
172 if h.HasRepoPermissionAny(
173 'repository.write', 'repository.admin')(self.db_repo_name):
173 'repository.write', 'repository.admin')(self.db_repo_name):
174 add_new = h.link_to(
174 add_new = h.link_to(
175 _('Click here to add a new file.'), _url, class_="alert-link")
175 _('Click here to add a new file.'), _url, class_="alert-link")
176 else:
176 else:
177 add_new = ""
177 add_new = ""
178
178
179 h.flash(h.literal(
179 h.flash(h.literal(
180 _('There are no files yet. %s') % add_new), category='warning')
180 _('There are no files yet. %s') % add_new), category='warning')
181 raise HTTPFound(
181 raise HTTPFound(
182 h.route_path('repo_summary', repo_name=self.db_repo_name))
182 h.route_path('repo_summary', repo_name=self.db_repo_name))
183
183
184 except (CommitDoesNotExistError, LookupError):
184 except (CommitDoesNotExistError, LookupError):
185 msg = _('No such commit exists for this repository')
185 msg = _('No such commit exists for this repository')
186 h.flash(msg, category='error')
186 h.flash(msg, category='error')
187 raise HTTPNotFound()
187 raise HTTPNotFound()
188 except RepositoryError as e:
188 except RepositoryError as e:
189 h.flash(safe_str(h.escape(e)), category='error')
189 h.flash(safe_str(h.escape(e)), category='error')
190 raise HTTPNotFound()
190 raise HTTPNotFound()
191
191
192 def _get_filenode_or_redirect(self, commit_obj, path):
192 def _get_filenode_or_redirect(self, commit_obj, path):
193 """
193 """
194 Returns file_node, if error occurs or given path is directory,
194 Returns file_node, if error occurs or given path is directory,
195 it'll redirect to top level path
195 it'll redirect to top level path
196 """
196 """
197 _ = self.request.translate
197 _ = self.request.translate
198
198
199 try:
199 try:
200 file_node = commit_obj.get_node(path)
200 file_node = commit_obj.get_node(path)
201 if file_node.is_dir():
201 if file_node.is_dir():
202 raise RepositoryError('The given path is a directory')
202 raise RepositoryError('The given path is a directory')
203 except CommitDoesNotExistError:
203 except CommitDoesNotExistError:
204 log.exception('No such commit exists for this repository')
204 log.exception('No such commit exists for this repository')
205 h.flash(_('No such commit exists for this repository'), category='error')
205 h.flash(_('No such commit exists for this repository'), category='error')
206 raise HTTPNotFound()
206 raise HTTPNotFound()
207 except RepositoryError as e:
207 except RepositoryError as e:
208 log.warning('Repository error while fetching filenode `%s`. Err:%s', path, e)
208 log.warning('Repository error while fetching filenode `%s`. Err:%s', path, e)
209 h.flash(safe_str(h.escape(e)), category='error')
209 h.flash(safe_str(h.escape(e)), category='error')
210 raise HTTPNotFound()
210 raise HTTPNotFound()
211
211
212 return file_node
212 return file_node
213
213
214 def _is_valid_head(self, commit_id, repo):
214 def _is_valid_head(self, commit_id, repo):
215 branch_name = sha_commit_id = ''
215 branch_name = sha_commit_id = ''
216 is_head = False
216 is_head = False
217 log.debug('Checking if commit_id `%s` is a head for %s.', commit_id, repo)
217 log.debug('Checking if commit_id `%s` is a head for %s.', commit_id, repo)
218
218
219 for _branch_name, branch_commit_id in repo.branches.items():
219 for _branch_name, branch_commit_id in repo.branches.items():
220 # simple case we pass in branch name, it's a HEAD
220 # simple case we pass in branch name, it's a HEAD
221 if commit_id == _branch_name:
221 if commit_id == _branch_name:
222 is_head = True
222 is_head = True
223 branch_name = _branch_name
223 branch_name = _branch_name
224 sha_commit_id = branch_commit_id
224 sha_commit_id = branch_commit_id
225 break
225 break
226 # case when we pass in full sha commit_id, which is a head
226 # case when we pass in full sha commit_id, which is a head
227 elif commit_id == branch_commit_id:
227 elif commit_id == branch_commit_id:
228 is_head = True
228 is_head = True
229 branch_name = _branch_name
229 branch_name = _branch_name
230 sha_commit_id = branch_commit_id
230 sha_commit_id = branch_commit_id
231 break
231 break
232
232
233 if h.is_svn(repo) and not repo.is_empty():
233 if h.is_svn(repo) and not repo.is_empty():
234 # Note: Subversion only has one head.
234 # Note: Subversion only has one head.
235 if commit_id == repo.get_commit(commit_idx=-1).raw_id:
235 if commit_id == repo.get_commit(commit_idx=-1).raw_id:
236 is_head = True
236 is_head = True
237 return branch_name, sha_commit_id, is_head
237 return branch_name, sha_commit_id, is_head
238
238
239 # checked branches, means we only need to try to get the branch/commit_sha
239 # checked branches, means we only need to try to get the branch/commit_sha
240 if not repo.is_empty():
240 if not repo.is_empty():
241 commit = repo.get_commit(commit_id=commit_id)
241 commit = repo.get_commit(commit_id=commit_id)
242 if commit:
242 if commit:
243 branch_name = commit.branch
243 branch_name = commit.branch
244 sha_commit_id = commit.raw_id
244 sha_commit_id = commit.raw_id
245
245
246 return branch_name, sha_commit_id, is_head
246 return branch_name, sha_commit_id, is_head
247
247
248 def _get_tree_at_commit(self, c, commit_id, f_path, full_load=False, at_rev=None):
248 def _get_tree_at_commit(self, c, commit_id, f_path, full_load=False, at_rev=None):
249
249
250 repo_id = self.db_repo.repo_id
250 repo_id = self.db_repo.repo_id
251 force_recache = self.get_recache_flag()
251 force_recache = self.get_recache_flag()
252
252
253 cache_seconds = safe_int(
253 cache_seconds = safe_int(
254 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
254 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
255 cache_on = not force_recache and cache_seconds > 0
255 cache_on = not force_recache and cache_seconds > 0
256 log.debug(
256 log.debug(
257 'Computing FILE TREE for repo_id %s commit_id `%s` and path `%s`'
257 'Computing FILE TREE for repo_id %s commit_id `%s` and path `%s`'
258 'with caching: %s[TTL: %ss]' % (
258 'with caching: %s[TTL: %ss]' % (
259 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
259 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
260
260
261 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
261 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
262 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
262 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
263
263
264 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
264 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
265 condition=cache_on)
265 condition=cache_on)
266 def compute_file_tree(ver, repo_id, commit_id, f_path, full_load, at_rev):
266 def compute_file_tree(ver, repo_id, commit_id, f_path, full_load, at_rev):
267 log.debug('Generating cached file tree at ver:%s for repo_id: %s, %s, %s',
267 log.debug('Generating cached file tree at ver:%s for repo_id: %s, %s, %s',
268 ver, repo_id, commit_id, f_path)
268 ver, repo_id, commit_id, f_path)
269
269
270 c.full_load = full_load
270 c.full_load = full_load
271 return render(
271 return render(
272 'rhodecode:templates/files/files_browser_tree.mako',
272 'rhodecode:templates/files/files_browser_tree.mako',
273 self._get_template_context(c), self.request, at_rev)
273 self._get_template_context(c), self.request, at_rev)
274
274
275 return compute_file_tree(
275 return compute_file_tree(
276 rc_cache.FILE_TREE_CACHE_VER, self.db_repo.repo_id, commit_id,
276 rc_cache.FILE_TREE_CACHE_VER, self.db_repo.repo_id, commit_id,
277 f_path, full_load, at_rev)
277 f_path, full_load, at_rev)
278
278
279 def _get_archive_spec(self, fname):
279 def _get_archive_spec(self, fname):
280 log.debug('Detecting archive spec for: `%s`', fname)
280 log.debug('Detecting archive spec for: `%s`', fname)
281
281
282 fileformat = None
282 fileformat = None
283 ext = None
283 ext = None
284 content_type = None
284 content_type = None
285 for a_type, content_type, extension in settings.ARCHIVE_SPECS:
285 for a_type, content_type, extension in settings.ARCHIVE_SPECS:
286
286
287 if fname.endswith(extension):
287 if fname.endswith(extension):
288 fileformat = a_type
288 fileformat = a_type
289 log.debug('archive is of type: %s', fileformat)
289 log.debug('archive is of type: %s', fileformat)
290 ext = extension
290 ext = extension
291 break
291 break
292
292
293 if not fileformat:
293 if not fileformat:
294 raise ValueError()
294 raise ValueError()
295
295
296 # left over part of whole fname is the commit
296 # left over part of whole fname is the commit
297 commit_id = fname[:-len(ext)]
297 commit_id = fname[:-len(ext)]
298
298
299 return commit_id, ext, fileformat, content_type
299 return commit_id, ext, fileformat, content_type
300
300
301 def create_pure_path(self, *parts):
301 def create_pure_path(self, *parts):
302 # Split paths and sanitize them, removing any ../ etc
302 # Split paths and sanitize them, removing any ../ etc
303 sanitized_path = [
303 sanitized_path = [
304 x for x in pathlib2.PurePath(*parts).parts
304 x for x in pathlib2.PurePath(*parts).parts
305 if x not in ['.', '..']]
305 if x not in ['.', '..']]
306
306
307 pure_path = pathlib2.PurePath(*sanitized_path)
307 pure_path = pathlib2.PurePath(*sanitized_path)
308 return pure_path
308 return pure_path
309
309
310 def _is_lf_enabled(self, target_repo):
310 def _is_lf_enabled(self, target_repo):
311 lf_enabled = False
311 lf_enabled = False
312
312
313 lf_key_for_vcs_map = {
313 lf_key_for_vcs_map = {
314 'hg': 'extensions_largefiles',
314 'hg': 'extensions_largefiles',
315 'git': 'vcs_git_lfs_enabled'
315 'git': 'vcs_git_lfs_enabled'
316 }
316 }
317
317
318 lf_key_for_vcs = lf_key_for_vcs_map.get(target_repo.repo_type)
318 lf_key_for_vcs = lf_key_for_vcs_map.get(target_repo.repo_type)
319
319
320 if lf_key_for_vcs:
320 if lf_key_for_vcs:
321 lf_enabled = self._get_repo_setting(target_repo, lf_key_for_vcs)
321 lf_enabled = self._get_repo_setting(target_repo, lf_key_for_vcs)
322
322
323 return lf_enabled
323 return lf_enabled
324
324
325 @LoginRequired()
325 @LoginRequired()
326 @HasRepoPermissionAnyDecorator(
326 @HasRepoPermissionAnyDecorator(
327 'repository.read', 'repository.write', 'repository.admin')
327 'repository.read', 'repository.write', 'repository.admin')
328 @view_config(
328 @view_config(
329 route_name='repo_archivefile', request_method='GET',
329 route_name='repo_archivefile', request_method='GET',
330 renderer=None)
330 renderer=None)
331 def repo_archivefile(self):
331 def repo_archivefile(self):
332 # archive cache config
332 # archive cache config
333 from rhodecode import CONFIG
333 from rhodecode import CONFIG
334 _ = self.request.translate
334 _ = self.request.translate
335 self.load_default_context()
335 self.load_default_context()
336 default_at_path = '/'
336 default_at_path = '/'
337 fname = self.request.matchdict['fname']
337 fname = self.request.matchdict['fname']
338 subrepos = self.request.GET.get('subrepos') == 'true'
338 subrepos = self.request.GET.get('subrepos') == 'true'
339 at_path = self.request.GET.get('at_path') or default_at_path
339 at_path = self.request.GET.get('at_path') or default_at_path
340
340
341 if not self.db_repo.enable_downloads:
341 if not self.db_repo.enable_downloads:
342 return Response(_('Downloads disabled'))
342 return Response(_('Downloads disabled'))
343
343
344 try:
344 try:
345 commit_id, ext, fileformat, content_type = \
345 commit_id, ext, fileformat, content_type = \
346 self._get_archive_spec(fname)
346 self._get_archive_spec(fname)
347 except ValueError:
347 except ValueError:
348 return Response(_('Unknown archive type for: `{}`').format(
348 return Response(_('Unknown archive type for: `{}`').format(
349 h.escape(fname)))
349 h.escape(fname)))
350
350
351 try:
351 try:
352 commit = self.rhodecode_vcs_repo.get_commit(commit_id)
352 commit = self.rhodecode_vcs_repo.get_commit(commit_id)
353 except CommitDoesNotExistError:
353 except CommitDoesNotExistError:
354 return Response(_('Unknown commit_id {}').format(
354 return Response(_('Unknown commit_id {}').format(
355 h.escape(commit_id)))
355 h.escape(commit_id)))
356 except EmptyRepositoryError:
356 except EmptyRepositoryError:
357 return Response(_('Empty repository'))
357 return Response(_('Empty repository'))
358
358
359 try:
359 try:
360 at_path = commit.get_node(at_path).path or default_at_path
360 at_path = commit.get_node(at_path).path or default_at_path
361 except Exception:
361 except Exception:
362 return Response(_('No node at path {} for this repository').format(at_path))
362 return Response(_('No node at path {} for this repository').format(at_path))
363
363
364 path_sha = sha1(at_path)[:8]
364 path_sha = sha1(at_path)[:8]
365
365
366 # original backward compat name of archive
366 # original backward compat name of archive
367 clean_name = safe_str(self.db_repo_name.replace('/', '_'))
367 clean_name = safe_str(self.db_repo_name.replace('/', '_'))
368 short_sha = safe_str(commit.short_id)
368 short_sha = safe_str(commit.short_id)
369
369
370 if at_path == default_at_path:
370 if at_path == default_at_path:
371 archive_name = '{}-{}{}{}'.format(
371 archive_name = '{}-{}{}{}'.format(
372 clean_name,
372 clean_name,
373 '-sub' if subrepos else '',
373 '-sub' if subrepos else '',
374 short_sha,
374 short_sha,
375 ext)
375 ext)
376 # custom path and new name
376 # custom path and new name
377 else:
377 else:
378 archive_name = '{}-{}{}-{}{}'.format(
378 archive_name = '{}-{}{}-{}{}'.format(
379 clean_name,
379 clean_name,
380 '-sub' if subrepos else '',
380 '-sub' if subrepos else '',
381 short_sha,
381 short_sha,
382 path_sha,
382 path_sha,
383 ext)
383 ext)
384
384
385 use_cached_archive = False
385 use_cached_archive = False
386 archive_cache_enabled = CONFIG.get(
386 archive_cache_enabled = CONFIG.get(
387 'archive_cache_dir') and not self.request.GET.get('no_cache')
387 'archive_cache_dir') and not self.request.GET.get('no_cache')
388 cached_archive_path = None
388 cached_archive_path = None
389
389
390 if archive_cache_enabled:
390 if archive_cache_enabled:
391 # check if we it's ok to write
391 # check if we it's ok to write
392 if not os.path.isdir(CONFIG['archive_cache_dir']):
392 if not os.path.isdir(CONFIG['archive_cache_dir']):
393 os.makedirs(CONFIG['archive_cache_dir'])
393 os.makedirs(CONFIG['archive_cache_dir'])
394 cached_archive_path = os.path.join(
394 cached_archive_path = os.path.join(
395 CONFIG['archive_cache_dir'], archive_name)
395 CONFIG['archive_cache_dir'], archive_name)
396 if os.path.isfile(cached_archive_path):
396 if os.path.isfile(cached_archive_path):
397 log.debug('Found cached archive in %s', cached_archive_path)
397 log.debug('Found cached archive in %s', cached_archive_path)
398 fd, archive = None, cached_archive_path
398 fd, archive = None, cached_archive_path
399 use_cached_archive = True
399 use_cached_archive = True
400 else:
400 else:
401 log.debug('Archive %s is not yet cached', archive_name)
401 log.debug('Archive %s is not yet cached', archive_name)
402
402
403 if not use_cached_archive:
403 if not use_cached_archive:
404 # generate new archive
404 # generate new archive
405 fd, archive = tempfile.mkstemp()
405 fd, archive = tempfile.mkstemp()
406 log.debug('Creating new temp archive in %s', archive)
406 log.debug('Creating new temp archive in %s', archive)
407 try:
407 try:
408 commit.archive_repo(archive, kind=fileformat, subrepos=subrepos,
408 commit.archive_repo(archive, kind=fileformat, subrepos=subrepos,
409 archive_at_path=at_path)
409 archive_at_path=at_path)
410 except ImproperArchiveTypeError:
410 except ImproperArchiveTypeError:
411 return _('Unknown archive type')
411 return _('Unknown archive type')
412 if archive_cache_enabled:
412 if archive_cache_enabled:
413 # if we generated the archive and we have cache enabled
413 # if we generated the archive and we have cache enabled
414 # let's use this for future
414 # let's use this for future
415 log.debug('Storing new archive in %s', cached_archive_path)
415 log.debug('Storing new archive in %s', cached_archive_path)
416 shutil.move(archive, cached_archive_path)
416 shutil.move(archive, cached_archive_path)
417 archive = cached_archive_path
417 archive = cached_archive_path
418
418
419 # store download action
419 # store download action
420 audit_logger.store_web(
420 audit_logger.store_web(
421 'repo.archive.download', action_data={
421 'repo.archive.download', action_data={
422 'user_agent': self.request.user_agent,
422 'user_agent': self.request.user_agent,
423 'archive_name': archive_name,
423 'archive_name': archive_name,
424 'archive_spec': fname,
424 'archive_spec': fname,
425 'archive_cached': use_cached_archive},
425 'archive_cached': use_cached_archive},
426 user=self._rhodecode_user,
426 user=self._rhodecode_user,
427 repo=self.db_repo,
427 repo=self.db_repo,
428 commit=True
428 commit=True
429 )
429 )
430
430
431 def get_chunked_archive(archive_path):
431 def get_chunked_archive(archive_path):
432 with open(archive_path, 'rb') as stream:
432 with open(archive_path, 'rb') as stream:
433 while True:
433 while True:
434 data = stream.read(16 * 1024)
434 data = stream.read(16 * 1024)
435 if not data:
435 if not data:
436 if fd: # fd means we used temporary file
436 if fd: # fd means we used temporary file
437 os.close(fd)
437 os.close(fd)
438 if not archive_cache_enabled:
438 if not archive_cache_enabled:
439 log.debug('Destroying temp archive %s', archive_path)
439 log.debug('Destroying temp archive %s', archive_path)
440 os.remove(archive_path)
440 os.remove(archive_path)
441 break
441 break
442 yield data
442 yield data
443
443
444 response = Response(app_iter=get_chunked_archive(archive))
444 response = Response(app_iter=get_chunked_archive(archive))
445 response.content_disposition = str(
445 response.content_disposition = str(
446 'attachment; filename=%s' % archive_name)
446 'attachment; filename=%s' % archive_name)
447 response.content_type = str(content_type)
447 response.content_type = str(content_type)
448
448
449 return response
449 return response
450
450
451 def _get_file_node(self, commit_id, f_path):
451 def _get_file_node(self, commit_id, f_path):
452 if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]:
452 if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]:
453 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
453 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
454 try:
454 try:
455 node = commit.get_node(f_path)
455 node = commit.get_node(f_path)
456 if node.is_dir():
456 if node.is_dir():
457 raise NodeError('%s path is a %s not a file'
457 raise NodeError('%s path is a %s not a file'
458 % (node, type(node)))
458 % (node, type(node)))
459 except NodeDoesNotExistError:
459 except NodeDoesNotExistError:
460 commit = EmptyCommit(
460 commit = EmptyCommit(
461 commit_id=commit_id,
461 commit_id=commit_id,
462 idx=commit.idx,
462 idx=commit.idx,
463 repo=commit.repository,
463 repo=commit.repository,
464 alias=commit.repository.alias,
464 alias=commit.repository.alias,
465 message=commit.message,
465 message=commit.message,
466 author=commit.author,
466 author=commit.author,
467 date=commit.date)
467 date=commit.date)
468 node = FileNode(f_path, '', commit=commit)
468 node = FileNode(f_path, '', commit=commit)
469 else:
469 else:
470 commit = EmptyCommit(
470 commit = EmptyCommit(
471 repo=self.rhodecode_vcs_repo,
471 repo=self.rhodecode_vcs_repo,
472 alias=self.rhodecode_vcs_repo.alias)
472 alias=self.rhodecode_vcs_repo.alias)
473 node = FileNode(f_path, '', commit=commit)
473 node = FileNode(f_path, '', commit=commit)
474 return node
474 return node
475
475
476 @LoginRequired()
476 @LoginRequired()
477 @HasRepoPermissionAnyDecorator(
477 @HasRepoPermissionAnyDecorator(
478 'repository.read', 'repository.write', 'repository.admin')
478 'repository.read', 'repository.write', 'repository.admin')
479 @view_config(
479 @view_config(
480 route_name='repo_files_diff', request_method='GET',
480 route_name='repo_files_diff', request_method='GET',
481 renderer=None)
481 renderer=None)
482 def repo_files_diff(self):
482 def repo_files_diff(self):
483 c = self.load_default_context()
483 c = self.load_default_context()
484 f_path = self._get_f_path(self.request.matchdict)
484 f_path = self._get_f_path(self.request.matchdict)
485 diff1 = self.request.GET.get('diff1', '')
485 diff1 = self.request.GET.get('diff1', '')
486 diff2 = self.request.GET.get('diff2', '')
486 diff2 = self.request.GET.get('diff2', '')
487
487
488 path1, diff1 = parse_path_ref(diff1, default_path=f_path)
488 path1, diff1 = parse_path_ref(diff1, default_path=f_path)
489
489
490 ignore_whitespace = str2bool(self.request.GET.get('ignorews'))
490 ignore_whitespace = str2bool(self.request.GET.get('ignorews'))
491 line_context = self.request.GET.get('context', 3)
491 line_context = self.request.GET.get('context', 3)
492
492
493 if not any((diff1, diff2)):
493 if not any((diff1, diff2)):
494 h.flash(
494 h.flash(
495 'Need query parameter "diff1" or "diff2" to generate a diff.',
495 'Need query parameter "diff1" or "diff2" to generate a diff.',
496 category='error')
496 category='error')
497 raise HTTPBadRequest()
497 raise HTTPBadRequest()
498
498
499 c.action = self.request.GET.get('diff')
499 c.action = self.request.GET.get('diff')
500 if c.action not in ['download', 'raw']:
500 if c.action not in ['download', 'raw']:
501 compare_url = h.route_path(
501 compare_url = h.route_path(
502 'repo_compare',
502 'repo_compare',
503 repo_name=self.db_repo_name,
503 repo_name=self.db_repo_name,
504 source_ref_type='rev',
504 source_ref_type='rev',
505 source_ref=diff1,
505 source_ref=diff1,
506 target_repo=self.db_repo_name,
506 target_repo=self.db_repo_name,
507 target_ref_type='rev',
507 target_ref_type='rev',
508 target_ref=diff2,
508 target_ref=diff2,
509 _query=dict(f_path=f_path))
509 _query=dict(f_path=f_path))
510 # redirect to new view if we render diff
510 # redirect to new view if we render diff
511 raise HTTPFound(compare_url)
511 raise HTTPFound(compare_url)
512
512
513 try:
513 try:
514 node1 = self._get_file_node(diff1, path1)
514 node1 = self._get_file_node(diff1, path1)
515 node2 = self._get_file_node(diff2, f_path)
515 node2 = self._get_file_node(diff2, f_path)
516 except (RepositoryError, NodeError):
516 except (RepositoryError, NodeError):
517 log.exception("Exception while trying to get node from repository")
517 log.exception("Exception while trying to get node from repository")
518 raise HTTPFound(
518 raise HTTPFound(
519 h.route_path('repo_files', repo_name=self.db_repo_name,
519 h.route_path('repo_files', repo_name=self.db_repo_name,
520 commit_id='tip', f_path=f_path))
520 commit_id='tip', f_path=f_path))
521
521
522 if all(isinstance(node.commit, EmptyCommit)
522 if all(isinstance(node.commit, EmptyCommit)
523 for node in (node1, node2)):
523 for node in (node1, node2)):
524 raise HTTPNotFound()
524 raise HTTPNotFound()
525
525
526 c.commit_1 = node1.commit
526 c.commit_1 = node1.commit
527 c.commit_2 = node2.commit
527 c.commit_2 = node2.commit
528
528
529 if c.action == 'download':
529 if c.action == 'download':
530 _diff = diffs.get_gitdiff(node1, node2,
530 _diff = diffs.get_gitdiff(node1, node2,
531 ignore_whitespace=ignore_whitespace,
531 ignore_whitespace=ignore_whitespace,
532 context=line_context)
532 context=line_context)
533 diff = diffs.DiffProcessor(_diff, format='gitdiff')
533 diff = diffs.DiffProcessor(_diff, format='gitdiff')
534
534
535 response = Response(self.path_filter.get_raw_patch(diff))
535 response = Response(self.path_filter.get_raw_patch(diff))
536 response.content_type = 'text/plain'
536 response.content_type = 'text/plain'
537 response.content_disposition = (
537 response.content_disposition = (
538 'attachment; filename=%s_%s_vs_%s.diff' % (f_path, diff1, diff2)
538 'attachment; filename=%s_%s_vs_%s.diff' % (f_path, diff1, diff2)
539 )
539 )
540 charset = self._get_default_encoding(c)
540 charset = self._get_default_encoding(c)
541 if charset:
541 if charset:
542 response.charset = charset
542 response.charset = charset
543 return response
543 return response
544
544
545 elif c.action == 'raw':
545 elif c.action == 'raw':
546 _diff = diffs.get_gitdiff(node1, node2,
546 _diff = diffs.get_gitdiff(node1, node2,
547 ignore_whitespace=ignore_whitespace,
547 ignore_whitespace=ignore_whitespace,
548 context=line_context)
548 context=line_context)
549 diff = diffs.DiffProcessor(_diff, format='gitdiff')
549 diff = diffs.DiffProcessor(_diff, format='gitdiff')
550
550
551 response = Response(self.path_filter.get_raw_patch(diff))
551 response = Response(self.path_filter.get_raw_patch(diff))
552 response.content_type = 'text/plain'
552 response.content_type = 'text/plain'
553 charset = self._get_default_encoding(c)
553 charset = self._get_default_encoding(c)
554 if charset:
554 if charset:
555 response.charset = charset
555 response.charset = charset
556 return response
556 return response
557
557
558 # in case we ever end up here
558 # in case we ever end up here
559 raise HTTPNotFound()
559 raise HTTPNotFound()
560
560
561 @LoginRequired()
561 @LoginRequired()
562 @HasRepoPermissionAnyDecorator(
562 @HasRepoPermissionAnyDecorator(
563 'repository.read', 'repository.write', 'repository.admin')
563 'repository.read', 'repository.write', 'repository.admin')
564 @view_config(
564 @view_config(
565 route_name='repo_files_diff_2way_redirect', request_method='GET',
565 route_name='repo_files_diff_2way_redirect', request_method='GET',
566 renderer=None)
566 renderer=None)
567 def repo_files_diff_2way_redirect(self):
567 def repo_files_diff_2way_redirect(self):
568 """
568 """
569 Kept only to make OLD links work
569 Kept only to make OLD links work
570 """
570 """
571 f_path = self._get_f_path_unchecked(self.request.matchdict)
571 f_path = self._get_f_path_unchecked(self.request.matchdict)
572 diff1 = self.request.GET.get('diff1', '')
572 diff1 = self.request.GET.get('diff1', '')
573 diff2 = self.request.GET.get('diff2', '')
573 diff2 = self.request.GET.get('diff2', '')
574
574
575 if not any((diff1, diff2)):
575 if not any((diff1, diff2)):
576 h.flash(
576 h.flash(
577 'Need query parameter "diff1" or "diff2" to generate a diff.',
577 'Need query parameter "diff1" or "diff2" to generate a diff.',
578 category='error')
578 category='error')
579 raise HTTPBadRequest()
579 raise HTTPBadRequest()
580
580
581 compare_url = h.route_path(
581 compare_url = h.route_path(
582 'repo_compare',
582 'repo_compare',
583 repo_name=self.db_repo_name,
583 repo_name=self.db_repo_name,
584 source_ref_type='rev',
584 source_ref_type='rev',
585 source_ref=diff1,
585 source_ref=diff1,
586 target_ref_type='rev',
586 target_ref_type='rev',
587 target_ref=diff2,
587 target_ref=diff2,
588 _query=dict(f_path=f_path, diffmode='sideside',
588 _query=dict(f_path=f_path, diffmode='sideside',
589 target_repo=self.db_repo_name,))
589 target_repo=self.db_repo_name,))
590 raise HTTPFound(compare_url)
590 raise HTTPFound(compare_url)
591
591
592 @LoginRequired()
592 @LoginRequired()
593 @HasRepoPermissionAnyDecorator(
593 @HasRepoPermissionAnyDecorator(
594 'repository.read', 'repository.write', 'repository.admin')
594 'repository.read', 'repository.write', 'repository.admin')
595 @view_config(
595 @view_config(
596 route_name='repo_files', request_method='GET',
596 route_name='repo_files', request_method='GET',
597 renderer=None)
597 renderer=None)
598 @view_config(
598 @view_config(
599 route_name='repo_files:default_path', request_method='GET',
599 route_name='repo_files:default_path', request_method='GET',
600 renderer=None)
600 renderer=None)
601 @view_config(
601 @view_config(
602 route_name='repo_files:default_commit', request_method='GET',
602 route_name='repo_files:default_commit', request_method='GET',
603 renderer=None)
603 renderer=None)
604 @view_config(
604 @view_config(
605 route_name='repo_files:rendered', request_method='GET',
605 route_name='repo_files:rendered', request_method='GET',
606 renderer=None)
606 renderer=None)
607 @view_config(
607 @view_config(
608 route_name='repo_files:annotated', request_method='GET',
608 route_name='repo_files:annotated', request_method='GET',
609 renderer=None)
609 renderer=None)
610 def repo_files(self):
610 def repo_files(self):
611 c = self.load_default_context()
611 c = self.load_default_context()
612
612
613 view_name = getattr(self.request.matched_route, 'name', None)
613 view_name = getattr(self.request.matched_route, 'name', None)
614
614
615 c.annotate = view_name == 'repo_files:annotated'
615 c.annotate = view_name == 'repo_files:annotated'
616 # default is false, but .rst/.md files later are auto rendered, we can
616 # default is false, but .rst/.md files later are auto rendered, we can
617 # overwrite auto rendering by setting this GET flag
617 # overwrite auto rendering by setting this GET flag
618 c.renderer = view_name == 'repo_files:rendered' or \
618 c.renderer = view_name == 'repo_files:rendered' or \
619 not self.request.GET.get('no-render', False)
619 not self.request.GET.get('no-render', False)
620
620
621 commit_id, f_path = self._get_commit_and_path()
621 commit_id, f_path = self._get_commit_and_path()
622
622
623 c.commit = self._get_commit_or_redirect(commit_id)
623 c.commit = self._get_commit_or_redirect(commit_id)
624 c.branch = self.request.GET.get('branch', None)
624 c.branch = self.request.GET.get('branch', None)
625 c.f_path = f_path
625 c.f_path = f_path
626 at_rev = self.request.GET.get('at')
626 at_rev = self.request.GET.get('at')
627
627
628 # prev link
628 # prev link
629 try:
629 try:
630 prev_commit = c.commit.prev(c.branch)
630 prev_commit = c.commit.prev(c.branch)
631 c.prev_commit = prev_commit
631 c.prev_commit = prev_commit
632 c.url_prev = h.route_path(
632 c.url_prev = h.route_path(
633 'repo_files', repo_name=self.db_repo_name,
633 'repo_files', repo_name=self.db_repo_name,
634 commit_id=prev_commit.raw_id, f_path=f_path)
634 commit_id=prev_commit.raw_id, f_path=f_path)
635 if c.branch:
635 if c.branch:
636 c.url_prev += '?branch=%s' % c.branch
636 c.url_prev += '?branch=%s' % c.branch
637 except (CommitDoesNotExistError, VCSError):
637 except (CommitDoesNotExistError, VCSError):
638 c.url_prev = '#'
638 c.url_prev = '#'
639 c.prev_commit = EmptyCommit()
639 c.prev_commit = EmptyCommit()
640
640
641 # next link
641 # next link
642 try:
642 try:
643 next_commit = c.commit.next(c.branch)
643 next_commit = c.commit.next(c.branch)
644 c.next_commit = next_commit
644 c.next_commit = next_commit
645 c.url_next = h.route_path(
645 c.url_next = h.route_path(
646 'repo_files', repo_name=self.db_repo_name,
646 'repo_files', repo_name=self.db_repo_name,
647 commit_id=next_commit.raw_id, f_path=f_path)
647 commit_id=next_commit.raw_id, f_path=f_path)
648 if c.branch:
648 if c.branch:
649 c.url_next += '?branch=%s' % c.branch
649 c.url_next += '?branch=%s' % c.branch
650 except (CommitDoesNotExistError, VCSError):
650 except (CommitDoesNotExistError, VCSError):
651 c.url_next = '#'
651 c.url_next = '#'
652 c.next_commit = EmptyCommit()
652 c.next_commit = EmptyCommit()
653
653
654 # files or dirs
654 # files or dirs
655 try:
655 try:
656 c.file = c.commit.get_node(f_path)
656 c.file = c.commit.get_node(f_path)
657 c.file_author = True
657 c.file_author = True
658 c.file_tree = ''
658 c.file_tree = ''
659
659
660 # load file content
660 # load file content
661 if c.file.is_file():
661 if c.file.is_file():
662 c.lf_node = {}
662 c.lf_node = {}
663
663
664 has_lf_enabled = self._is_lf_enabled(self.db_repo)
664 has_lf_enabled = self._is_lf_enabled(self.db_repo)
665 if has_lf_enabled:
665 if has_lf_enabled:
666 c.lf_node = c.file.get_largefile_node()
666 c.lf_node = c.file.get_largefile_node()
667
667
668 c.file_source_page = 'true'
668 c.file_source_page = 'true'
669 c.file_last_commit = c.file.last_commit
669 c.file_last_commit = c.file.last_commit
670
670
671 c.file_size_too_big = c.file.size > c.visual.cut_off_limit_file
671 c.file_size_too_big = c.file.size > c.visual.cut_off_limit_file
672
672
673 if not (c.file_size_too_big or c.file.is_binary):
673 if not (c.file_size_too_big or c.file.is_binary):
674 if c.annotate: # annotation has precedence over renderer
674 if c.annotate: # annotation has precedence over renderer
675 c.annotated_lines = filenode_as_annotated_lines_tokens(
675 c.annotated_lines = filenode_as_annotated_lines_tokens(
676 c.file
676 c.file
677 )
677 )
678 else:
678 else:
679 c.renderer = (
679 c.renderer = (
680 c.renderer and h.renderer_from_filename(c.file.path)
680 c.renderer and h.renderer_from_filename(c.file.path)
681 )
681 )
682 if not c.renderer:
682 if not c.renderer:
683 c.lines = filenode_as_lines_tokens(c.file)
683 c.lines = filenode_as_lines_tokens(c.file)
684
684
685 _branch_name, _sha_commit_id, is_head = self._is_valid_head(
685 _branch_name, _sha_commit_id, is_head = self._is_valid_head(
686 commit_id, self.rhodecode_vcs_repo)
686 commit_id, self.rhodecode_vcs_repo)
687 c.on_branch_head = is_head
687 c.on_branch_head = is_head
688
688
689 branch = c.commit.branch if (
689 branch = c.commit.branch if (
690 c.commit.branch and '/' not in c.commit.branch) else None
690 c.commit.branch and '/' not in c.commit.branch) else None
691 c.branch_or_raw_id = branch or c.commit.raw_id
691 c.branch_or_raw_id = branch or c.commit.raw_id
692 c.branch_name = c.commit.branch or h.short_id(c.commit.raw_id)
692 c.branch_name = c.commit.branch or h.short_id(c.commit.raw_id)
693
693
694 author = c.file_last_commit.author
694 author = c.file_last_commit.author
695 c.authors = [[
695 c.authors = [[
696 h.email(author),
696 h.email(author),
697 h.person(author, 'username_or_name_or_email'),
697 h.person(author, 'username_or_name_or_email'),
698 1
698 1
699 ]]
699 ]]
700
700
701 else: # load tree content at path
701 else: # load tree content at path
702 c.file_source_page = 'false'
702 c.file_source_page = 'false'
703 c.authors = []
703 c.authors = []
704 # this loads a simple tree without metadata to speed things up
704 # this loads a simple tree without metadata to speed things up
705 # later via ajax we call repo_nodetree_full and fetch whole
705 # later via ajax we call repo_nodetree_full and fetch whole
706 c.file_tree = self._get_tree_at_commit(c, c.commit.raw_id, f_path, at_rev=at_rev)
706 c.file_tree = self._get_tree_at_commit(c, c.commit.raw_id, f_path, at_rev=at_rev)
707
707
708 c.readme_data, c.readme_file = \
708 c.readme_data, c.readme_file = \
709 self._get_readme_data(self.db_repo, c.visual.default_renderer,
709 self._get_readme_data(self.db_repo, c.visual.default_renderer,
710 c.commit.raw_id, f_path)
710 c.commit.raw_id, f_path)
711
711
712 except RepositoryError as e:
712 except RepositoryError as e:
713 h.flash(safe_str(h.escape(e)), category='error')
713 h.flash(safe_str(h.escape(e)), category='error')
714 raise HTTPNotFound()
714 raise HTTPNotFound()
715
715
716 if self.request.environ.get('HTTP_X_PJAX'):
716 if self.request.environ.get('HTTP_X_PJAX'):
717 html = render('rhodecode:templates/files/files_pjax.mako',
717 html = render('rhodecode:templates/files/files_pjax.mako',
718 self._get_template_context(c), self.request)
718 self._get_template_context(c), self.request)
719 else:
719 else:
720 html = render('rhodecode:templates/files/files.mako',
720 html = render('rhodecode:templates/files/files.mako',
721 self._get_template_context(c), self.request)
721 self._get_template_context(c), self.request)
722 return Response(html)
722 return Response(html)
723
723
724 @HasRepoPermissionAnyDecorator(
724 @HasRepoPermissionAnyDecorator(
725 'repository.read', 'repository.write', 'repository.admin')
725 'repository.read', 'repository.write', 'repository.admin')
726 @view_config(
726 @view_config(
727 route_name='repo_files:annotated_previous', request_method='GET',
727 route_name='repo_files:annotated_previous', request_method='GET',
728 renderer=None)
728 renderer=None)
729 def repo_files_annotated_previous(self):
729 def repo_files_annotated_previous(self):
730 self.load_default_context()
730 self.load_default_context()
731
731
732 commit_id, f_path = self._get_commit_and_path()
732 commit_id, f_path = self._get_commit_and_path()
733 commit = self._get_commit_or_redirect(commit_id)
733 commit = self._get_commit_or_redirect(commit_id)
734 prev_commit_id = commit.raw_id
734 prev_commit_id = commit.raw_id
735 line_anchor = self.request.GET.get('line_anchor')
735 line_anchor = self.request.GET.get('line_anchor')
736 is_file = False
736 is_file = False
737 try:
737 try:
738 _file = commit.get_node(f_path)
738 _file = commit.get_node(f_path)
739 is_file = _file.is_file()
739 is_file = _file.is_file()
740 except (NodeDoesNotExistError, CommitDoesNotExistError, VCSError):
740 except (NodeDoesNotExistError, CommitDoesNotExistError, VCSError):
741 pass
741 pass
742
742
743 if is_file:
743 if is_file:
744 history = commit.get_path_history(f_path)
744 history = commit.get_path_history(f_path)
745 prev_commit_id = history[1].raw_id \
745 prev_commit_id = history[1].raw_id \
746 if len(history) > 1 else prev_commit_id
746 if len(history) > 1 else prev_commit_id
747 prev_url = h.route_path(
747 prev_url = h.route_path(
748 'repo_files:annotated', repo_name=self.db_repo_name,
748 'repo_files:annotated', repo_name=self.db_repo_name,
749 commit_id=prev_commit_id, f_path=f_path,
749 commit_id=prev_commit_id, f_path=f_path,
750 _anchor='L{}'.format(line_anchor))
750 _anchor='L{}'.format(line_anchor))
751
751
752 raise HTTPFound(prev_url)
752 raise HTTPFound(prev_url)
753
753
754 @LoginRequired()
754 @LoginRequired()
755 @HasRepoPermissionAnyDecorator(
755 @HasRepoPermissionAnyDecorator(
756 'repository.read', 'repository.write', 'repository.admin')
756 'repository.read', 'repository.write', 'repository.admin')
757 @view_config(
757 @view_config(
758 route_name='repo_nodetree_full', request_method='GET',
758 route_name='repo_nodetree_full', request_method='GET',
759 renderer=None, xhr=True)
759 renderer=None, xhr=True)
760 @view_config(
760 @view_config(
761 route_name='repo_nodetree_full:default_path', request_method='GET',
761 route_name='repo_nodetree_full:default_path', request_method='GET',
762 renderer=None, xhr=True)
762 renderer=None, xhr=True)
763 def repo_nodetree_full(self):
763 def repo_nodetree_full(self):
764 """
764 """
765 Returns rendered html of file tree that contains commit date,
765 Returns rendered html of file tree that contains commit date,
766 author, commit_id for the specified combination of
766 author, commit_id for the specified combination of
767 repo, commit_id and file path
767 repo, commit_id and file path
768 """
768 """
769 c = self.load_default_context()
769 c = self.load_default_context()
770
770
771 commit_id, f_path = self._get_commit_and_path()
771 commit_id, f_path = self._get_commit_and_path()
772 commit = self._get_commit_or_redirect(commit_id)
772 commit = self._get_commit_or_redirect(commit_id)
773 try:
773 try:
774 dir_node = commit.get_node(f_path)
774 dir_node = commit.get_node(f_path)
775 except RepositoryError as e:
775 except RepositoryError as e:
776 return Response('error: {}'.format(h.escape(safe_str(e))))
776 return Response('error: {}'.format(h.escape(safe_str(e))))
777
777
778 if dir_node.is_file():
778 if dir_node.is_file():
779 return Response('')
779 return Response('')
780
780
781 c.file = dir_node
781 c.file = dir_node
782 c.commit = commit
782 c.commit = commit
783 at_rev = self.request.GET.get('at')
783 at_rev = self.request.GET.get('at')
784
784
785 html = self._get_tree_at_commit(
785 html = self._get_tree_at_commit(
786 c, commit.raw_id, dir_node.path, full_load=True, at_rev=at_rev)
786 c, commit.raw_id, dir_node.path, full_load=True, at_rev=at_rev)
787
787
788 return Response(html)
788 return Response(html)
789
789
790 def _get_attachement_headers(self, f_path):
790 def _get_attachement_headers(self, f_path):
791 f_name = safe_str(f_path.split(Repository.NAME_SEP)[-1])
791 f_name = safe_str(f_path.split(Repository.NAME_SEP)[-1])
792 safe_path = f_name.replace('"', '\\"')
792 safe_path = f_name.replace('"', '\\"')
793 encoded_path = urllib.quote(f_name)
793 encoded_path = urllib.quote(f_name)
794
794
795 return "attachment; " \
795 return "attachment; " \
796 "filename=\"{}\"; " \
796 "filename=\"{}\"; " \
797 "filename*=UTF-8\'\'{}".format(safe_path, encoded_path)
797 "filename*=UTF-8\'\'{}".format(safe_path, encoded_path)
798
798
799 @LoginRequired()
799 @LoginRequired()
800 @HasRepoPermissionAnyDecorator(
800 @HasRepoPermissionAnyDecorator(
801 'repository.read', 'repository.write', 'repository.admin')
801 'repository.read', 'repository.write', 'repository.admin')
802 @view_config(
802 @view_config(
803 route_name='repo_file_raw', request_method='GET',
803 route_name='repo_file_raw', request_method='GET',
804 renderer=None)
804 renderer=None)
805 def repo_file_raw(self):
805 def repo_file_raw(self):
806 """
806 """
807 Action for show as raw, some mimetypes are "rendered",
807 Action for show as raw, some mimetypes are "rendered",
808 those include images, icons.
808 those include images, icons.
809 """
809 """
810 c = self.load_default_context()
810 c = self.load_default_context()
811
811
812 commit_id, f_path = self._get_commit_and_path()
812 commit_id, f_path = self._get_commit_and_path()
813 commit = self._get_commit_or_redirect(commit_id)
813 commit = self._get_commit_or_redirect(commit_id)
814 file_node = self._get_filenode_or_redirect(commit, f_path)
814 file_node = self._get_filenode_or_redirect(commit, f_path)
815
815
816 raw_mimetype_mapping = {
816 raw_mimetype_mapping = {
817 # map original mimetype to a mimetype used for "show as raw"
817 # map original mimetype to a mimetype used for "show as raw"
818 # you can also provide a content-disposition to override the
818 # you can also provide a content-disposition to override the
819 # default "attachment" disposition.
819 # default "attachment" disposition.
820 # orig_type: (new_type, new_dispo)
820 # orig_type: (new_type, new_dispo)
821
821
822 # show images inline:
822 # show images inline:
823 # Do not re-add SVG: it is unsafe and permits XSS attacks. One can
823 # Do not re-add SVG: it is unsafe and permits XSS attacks. One can
824 # for example render an SVG with javascript inside or even render
824 # for example render an SVG with javascript inside or even render
825 # HTML.
825 # HTML.
826 'image/x-icon': ('image/x-icon', 'inline'),
826 'image/x-icon': ('image/x-icon', 'inline'),
827 'image/png': ('image/png', 'inline'),
827 'image/png': ('image/png', 'inline'),
828 'image/gif': ('image/gif', 'inline'),
828 'image/gif': ('image/gif', 'inline'),
829 'image/jpeg': ('image/jpeg', 'inline'),
829 'image/jpeg': ('image/jpeg', 'inline'),
830 'application/pdf': ('application/pdf', 'inline'),
830 'application/pdf': ('application/pdf', 'inline'),
831 }
831 }
832
832
833 mimetype = file_node.mimetype
833 mimetype = file_node.mimetype
834 try:
834 try:
835 mimetype, disposition = raw_mimetype_mapping[mimetype]
835 mimetype, disposition = raw_mimetype_mapping[mimetype]
836 except KeyError:
836 except KeyError:
837 # we don't know anything special about this, handle it safely
837 # we don't know anything special about this, handle it safely
838 if file_node.is_binary:
838 if file_node.is_binary:
839 # do same as download raw for binary files
839 # do same as download raw for binary files
840 mimetype, disposition = 'application/octet-stream', 'attachment'
840 mimetype, disposition = 'application/octet-stream', 'attachment'
841 else:
841 else:
842 # do not just use the original mimetype, but force text/plain,
842 # do not just use the original mimetype, but force text/plain,
843 # otherwise it would serve text/html and that might be unsafe.
843 # otherwise it would serve text/html and that might be unsafe.
844 # Note: underlying vcs library fakes text/plain mimetype if the
844 # Note: underlying vcs library fakes text/plain mimetype if the
845 # mimetype can not be determined and it thinks it is not
845 # mimetype can not be determined and it thinks it is not
846 # binary.This might lead to erroneous text display in some
846 # binary.This might lead to erroneous text display in some
847 # cases, but helps in other cases, like with text files
847 # cases, but helps in other cases, like with text files
848 # without extension.
848 # without extension.
849 mimetype, disposition = 'text/plain', 'inline'
849 mimetype, disposition = 'text/plain', 'inline'
850
850
851 if disposition == 'attachment':
851 if disposition == 'attachment':
852 disposition = self._get_attachement_headers(f_path)
852 disposition = self._get_attachement_headers(f_path)
853
853
854 stream_content = file_node.stream_bytes()
854 stream_content = file_node.stream_bytes()
855
855
856 response = Response(app_iter=stream_content)
856 response = Response(app_iter=stream_content)
857 response.content_disposition = disposition
857 response.content_disposition = disposition
858 response.content_type = mimetype
858 response.content_type = mimetype
859
859
860 charset = self._get_default_encoding(c)
860 charset = self._get_default_encoding(c)
861 if charset:
861 if charset:
862 response.charset = charset
862 response.charset = charset
863
863
864 return response
864 return response
865
865
866 @LoginRequired()
866 @LoginRequired()
867 @HasRepoPermissionAnyDecorator(
867 @HasRepoPermissionAnyDecorator(
868 'repository.read', 'repository.write', 'repository.admin')
868 'repository.read', 'repository.write', 'repository.admin')
869 @view_config(
869 @view_config(
870 route_name='repo_file_download', request_method='GET',
870 route_name='repo_file_download', request_method='GET',
871 renderer=None)
871 renderer=None)
872 @view_config(
872 @view_config(
873 route_name='repo_file_download:legacy', request_method='GET',
873 route_name='repo_file_download:legacy', request_method='GET',
874 renderer=None)
874 renderer=None)
875 def repo_file_download(self):
875 def repo_file_download(self):
876 c = self.load_default_context()
876 c = self.load_default_context()
877
877
878 commit_id, f_path = self._get_commit_and_path()
878 commit_id, f_path = self._get_commit_and_path()
879 commit = self._get_commit_or_redirect(commit_id)
879 commit = self._get_commit_or_redirect(commit_id)
880 file_node = self._get_filenode_or_redirect(commit, f_path)
880 file_node = self._get_filenode_or_redirect(commit, f_path)
881
881
882 if self.request.GET.get('lf'):
882 if self.request.GET.get('lf'):
883 # only if lf get flag is passed, we download this file
883 # only if lf get flag is passed, we download this file
884 # as LFS/Largefile
884 # as LFS/Largefile
885 lf_node = file_node.get_largefile_node()
885 lf_node = file_node.get_largefile_node()
886 if lf_node:
886 if lf_node:
887 # overwrite our pointer with the REAL large-file
887 # overwrite our pointer with the REAL large-file
888 file_node = lf_node
888 file_node = lf_node
889
889
890 disposition = self._get_attachement_headers(f_path)
890 disposition = self._get_attachement_headers(f_path)
891
891
892 stream_content = file_node.stream_bytes()
892 stream_content = file_node.stream_bytes()
893
893
894 response = Response(app_iter=stream_content)
894 response = Response(app_iter=stream_content)
895 response.content_disposition = disposition
895 response.content_disposition = disposition
896 response.content_type = file_node.mimetype
896 response.content_type = file_node.mimetype
897
897
898 charset = self._get_default_encoding(c)
898 charset = self._get_default_encoding(c)
899 if charset:
899 if charset:
900 response.charset = charset
900 response.charset = charset
901
901
902 return response
902 return response
903
903
904 def _get_nodelist_at_commit(self, repo_name, repo_id, commit_id, f_path):
904 def _get_nodelist_at_commit(self, repo_name, repo_id, commit_id, f_path):
905
905
906 cache_seconds = safe_int(
906 cache_seconds = safe_int(
907 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
907 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
908 cache_on = cache_seconds > 0
908 cache_on = cache_seconds > 0
909 log.debug(
909 log.debug(
910 'Computing FILE SEARCH for repo_id %s commit_id `%s` and path `%s`'
910 'Computing FILE SEARCH for repo_id %s commit_id `%s` and path `%s`'
911 'with caching: %s[TTL: %ss]' % (
911 'with caching: %s[TTL: %ss]' % (
912 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
912 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
913
913
914 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
914 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
915 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
915 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
916
916
917 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
917 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
918 condition=cache_on)
918 condition=cache_on)
919 def compute_file_search(repo_id, commit_id, f_path):
919 def compute_file_search(repo_id, commit_id, f_path):
920 log.debug('Generating cached nodelist for repo_id:%s, %s, %s',
920 log.debug('Generating cached nodelist for repo_id:%s, %s, %s',
921 repo_id, commit_id, f_path)
921 repo_id, commit_id, f_path)
922 try:
922 try:
923 _d, _f = ScmModel().get_quick_filter_nodes(repo_name, commit_id, f_path)
923 _d, _f = ScmModel().get_quick_filter_nodes(repo_name, commit_id, f_path)
924 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
924 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
925 log.exception(safe_str(e))
925 log.exception(safe_str(e))
926 h.flash(safe_str(h.escape(e)), category='error')
926 h.flash(safe_str(h.escape(e)), category='error')
927 raise HTTPFound(h.route_path(
927 raise HTTPFound(h.route_path(
928 'repo_files', repo_name=self.db_repo_name,
928 'repo_files', repo_name=self.db_repo_name,
929 commit_id='tip', f_path='/'))
929 commit_id='tip', f_path='/'))
930
930
931 return _d + _f
931 return _d + _f
932
932
933 result = compute_file_search(self.db_repo.repo_id, commit_id, f_path)
933 result = compute_file_search(self.db_repo.repo_id, commit_id, f_path)
934 return filter(lambda n: self.path_filter.path_access_allowed(n['name']), result)
934 return filter(lambda n: self.path_filter.path_access_allowed(n['name']), result)
935
935
936 @LoginRequired()
936 @LoginRequired()
937 @HasRepoPermissionAnyDecorator(
937 @HasRepoPermissionAnyDecorator(
938 'repository.read', 'repository.write', 'repository.admin')
938 'repository.read', 'repository.write', 'repository.admin')
939 @view_config(
939 @view_config(
940 route_name='repo_files_nodelist', request_method='GET',
940 route_name='repo_files_nodelist', request_method='GET',
941 renderer='json_ext', xhr=True)
941 renderer='json_ext', xhr=True)
942 def repo_nodelist(self):
942 def repo_nodelist(self):
943 self.load_default_context()
943 self.load_default_context()
944
944
945 commit_id, f_path = self._get_commit_and_path()
945 commit_id, f_path = self._get_commit_and_path()
946 commit = self._get_commit_or_redirect(commit_id)
946 commit = self._get_commit_or_redirect(commit_id)
947
947
948 metadata = self._get_nodelist_at_commit(
948 metadata = self._get_nodelist_at_commit(
949 self.db_repo_name, self.db_repo.repo_id, commit.raw_id, f_path)
949 self.db_repo_name, self.db_repo.repo_id, commit.raw_id, f_path)
950 return {'nodes': metadata}
950 return {'nodes': metadata}
951
951
952 def _create_references(self, branches_or_tags, symbolic_reference, f_path, ref_type):
952 def _create_references(self, branches_or_tags, symbolic_reference, f_path, ref_type):
953 items = []
953 items = []
954 for name, commit_id in branches_or_tags.items():
954 for name, commit_id in branches_or_tags.items():
955 sym_ref = symbolic_reference(commit_id, name, f_path, ref_type)
955 sym_ref = symbolic_reference(commit_id, name, f_path, ref_type)
956 items.append((sym_ref, name, ref_type))
956 items.append((sym_ref, name, ref_type))
957 return items
957 return items
958
958
959 def _symbolic_reference(self, commit_id, name, f_path, ref_type):
959 def _symbolic_reference(self, commit_id, name, f_path, ref_type):
960 return commit_id
960 return commit_id
961
961
962 def _symbolic_reference_svn(self, commit_id, name, f_path, ref_type):
962 def _symbolic_reference_svn(self, commit_id, name, f_path, ref_type):
963 return commit_id
963 return commit_id
964
964
965 # NOTE(dan): old code we used in "diff" mode compare
965 # NOTE(dan): old code we used in "diff" mode compare
966 new_f_path = vcspath.join(name, f_path)
966 new_f_path = vcspath.join(name, f_path)
967 return u'%s@%s' % (new_f_path, commit_id)
967 return u'%s@%s' % (new_f_path, commit_id)
968
968
969 def _get_node_history(self, commit_obj, f_path, commits=None):
969 def _get_node_history(self, commit_obj, f_path, commits=None):
970 """
970 """
971 get commit history for given node
971 get commit history for given node
972
972
973 :param commit_obj: commit to calculate history
973 :param commit_obj: commit to calculate history
974 :param f_path: path for node to calculate history for
974 :param f_path: path for node to calculate history for
975 :param commits: if passed don't calculate history and take
975 :param commits: if passed don't calculate history and take
976 commits defined in this list
976 commits defined in this list
977 """
977 """
978 _ = self.request.translate
978 _ = self.request.translate
979
979
980 # calculate history based on tip
980 # calculate history based on tip
981 tip = self.rhodecode_vcs_repo.get_commit()
981 tip = self.rhodecode_vcs_repo.get_commit()
982 if commits is None:
982 if commits is None:
983 pre_load = ["author", "branch"]
983 pre_load = ["author", "branch"]
984 try:
984 try:
985 commits = tip.get_path_history(f_path, pre_load=pre_load)
985 commits = tip.get_path_history(f_path, pre_load=pre_load)
986 except (NodeDoesNotExistError, CommitError):
986 except (NodeDoesNotExistError, CommitError):
987 # this node is not present at tip!
987 # this node is not present at tip!
988 commits = commit_obj.get_path_history(f_path, pre_load=pre_load)
988 commits = commit_obj.get_path_history(f_path, pre_load=pre_load)
989
989
990 history = []
990 history = []
991 commits_group = ([], _("Changesets"))
991 commits_group = ([], _("Changesets"))
992 for commit in commits:
992 for commit in commits:
993 branch = ' (%s)' % commit.branch if commit.branch else ''
993 branch = ' (%s)' % commit.branch if commit.branch else ''
994 n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch)
994 n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch)
995 commits_group[0].append((commit.raw_id, n_desc, 'sha'))
995 commits_group[0].append((commit.raw_id, n_desc, 'sha'))
996 history.append(commits_group)
996 history.append(commits_group)
997
997
998 symbolic_reference = self._symbolic_reference
998 symbolic_reference = self._symbolic_reference
999
999
1000 if self.rhodecode_vcs_repo.alias == 'svn':
1000 if self.rhodecode_vcs_repo.alias == 'svn':
1001 adjusted_f_path = RepoFilesView.adjust_file_path_for_svn(
1001 adjusted_f_path = RepoFilesView.adjust_file_path_for_svn(
1002 f_path, self.rhodecode_vcs_repo)
1002 f_path, self.rhodecode_vcs_repo)
1003 if adjusted_f_path != f_path:
1003 if adjusted_f_path != f_path:
1004 log.debug(
1004 log.debug(
1005 'Recognized svn tag or branch in file "%s", using svn '
1005 'Recognized svn tag or branch in file "%s", using svn '
1006 'specific symbolic references', f_path)
1006 'specific symbolic references', f_path)
1007 f_path = adjusted_f_path
1007 f_path = adjusted_f_path
1008 symbolic_reference = self._symbolic_reference_svn
1008 symbolic_reference = self._symbolic_reference_svn
1009
1009
1010 branches = self._create_references(
1010 branches = self._create_references(
1011 self.rhodecode_vcs_repo.branches, symbolic_reference, f_path, 'branch')
1011 self.rhodecode_vcs_repo.branches, symbolic_reference, f_path, 'branch')
1012 branches_group = (branches, _("Branches"))
1012 branches_group = (branches, _("Branches"))
1013
1013
1014 tags = self._create_references(
1014 tags = self._create_references(
1015 self.rhodecode_vcs_repo.tags, symbolic_reference, f_path, 'tag')
1015 self.rhodecode_vcs_repo.tags, symbolic_reference, f_path, 'tag')
1016 tags_group = (tags, _("Tags"))
1016 tags_group = (tags, _("Tags"))
1017
1017
1018 history.append(branches_group)
1018 history.append(branches_group)
1019 history.append(tags_group)
1019 history.append(tags_group)
1020
1020
1021 return history, commits
1021 return history, commits
1022
1022
1023 @LoginRequired()
1023 @LoginRequired()
1024 @HasRepoPermissionAnyDecorator(
1024 @HasRepoPermissionAnyDecorator(
1025 'repository.read', 'repository.write', 'repository.admin')
1025 'repository.read', 'repository.write', 'repository.admin')
1026 @view_config(
1026 @view_config(
1027 route_name='repo_file_history', request_method='GET',
1027 route_name='repo_file_history', request_method='GET',
1028 renderer='json_ext')
1028 renderer='json_ext')
1029 def repo_file_history(self):
1029 def repo_file_history(self):
1030 self.load_default_context()
1030 self.load_default_context()
1031
1031
1032 commit_id, f_path = self._get_commit_and_path()
1032 commit_id, f_path = self._get_commit_and_path()
1033 commit = self._get_commit_or_redirect(commit_id)
1033 commit = self._get_commit_or_redirect(commit_id)
1034 file_node = self._get_filenode_or_redirect(commit, f_path)
1034 file_node = self._get_filenode_or_redirect(commit, f_path)
1035
1035
1036 if file_node.is_file():
1036 if file_node.is_file():
1037 file_history, _hist = self._get_node_history(commit, f_path)
1037 file_history, _hist = self._get_node_history(commit, f_path)
1038
1038
1039 res = []
1039 res = []
1040 for section_items, section in file_history:
1040 for section_items, section in file_history:
1041 items = []
1041 items = []
1042 for obj_id, obj_text, obj_type in section_items:
1042 for obj_id, obj_text, obj_type in section_items:
1043 at_rev = ''
1043 at_rev = ''
1044 if obj_type in ['branch', 'bookmark', 'tag']:
1044 if obj_type in ['branch', 'bookmark', 'tag']:
1045 at_rev = obj_text
1045 at_rev = obj_text
1046 entry = {
1046 entry = {
1047 'id': obj_id,
1047 'id': obj_id,
1048 'text': obj_text,
1048 'text': obj_text,
1049 'type': obj_type,
1049 'type': obj_type,
1050 'at_rev': at_rev
1050 'at_rev': at_rev
1051 }
1051 }
1052
1052
1053 items.append(entry)
1053 items.append(entry)
1054
1054
1055 res.append({
1055 res.append({
1056 'text': section,
1056 'text': section,
1057 'children': items
1057 'children': items
1058 })
1058 })
1059
1059
1060 data = {
1060 data = {
1061 'more': False,
1061 'more': False,
1062 'results': res
1062 'results': res
1063 }
1063 }
1064 return data
1064 return data
1065
1065
1066 log.warning('Cannot fetch history for directory')
1066 log.warning('Cannot fetch history for directory')
1067 raise HTTPBadRequest()
1067 raise HTTPBadRequest()
1068
1068
1069 @LoginRequired()
1069 @LoginRequired()
1070 @HasRepoPermissionAnyDecorator(
1070 @HasRepoPermissionAnyDecorator(
1071 'repository.read', 'repository.write', 'repository.admin')
1071 'repository.read', 'repository.write', 'repository.admin')
1072 @view_config(
1072 @view_config(
1073 route_name='repo_file_authors', request_method='GET',
1073 route_name='repo_file_authors', request_method='GET',
1074 renderer='rhodecode:templates/files/file_authors_box.mako')
1074 renderer='rhodecode:templates/files/file_authors_box.mako')
1075 def repo_file_authors(self):
1075 def repo_file_authors(self):
1076 c = self.load_default_context()
1076 c = self.load_default_context()
1077
1077
1078 commit_id, f_path = self._get_commit_and_path()
1078 commit_id, f_path = self._get_commit_and_path()
1079 commit = self._get_commit_or_redirect(commit_id)
1079 commit = self._get_commit_or_redirect(commit_id)
1080 file_node = self._get_filenode_or_redirect(commit, f_path)
1080 file_node = self._get_filenode_or_redirect(commit, f_path)
1081
1081
1082 if not file_node.is_file():
1082 if not file_node.is_file():
1083 raise HTTPBadRequest()
1083 raise HTTPBadRequest()
1084
1084
1085 c.file_last_commit = file_node.last_commit
1085 c.file_last_commit = file_node.last_commit
1086 if self.request.GET.get('annotate') == '1':
1086 if self.request.GET.get('annotate') == '1':
1087 # use _hist from annotation if annotation mode is on
1087 # use _hist from annotation if annotation mode is on
1088 commit_ids = set(x[1] for x in file_node.annotate)
1088 commit_ids = set(x[1] for x in file_node.annotate)
1089 _hist = (
1089 _hist = (
1090 self.rhodecode_vcs_repo.get_commit(commit_id)
1090 self.rhodecode_vcs_repo.get_commit(commit_id)
1091 for commit_id in commit_ids)
1091 for commit_id in commit_ids)
1092 else:
1092 else:
1093 _f_history, _hist = self._get_node_history(commit, f_path)
1093 _f_history, _hist = self._get_node_history(commit, f_path)
1094 c.file_author = False
1094 c.file_author = False
1095
1095
1096 unique = collections.OrderedDict()
1096 unique = collections.OrderedDict()
1097 for commit in _hist:
1097 for commit in _hist:
1098 author = commit.author
1098 author = commit.author
1099 if author not in unique:
1099 if author not in unique:
1100 unique[commit.author] = [
1100 unique[commit.author] = [
1101 h.email(author),
1101 h.email(author),
1102 h.person(author, 'username_or_name_or_email'),
1102 h.person(author, 'username_or_name_or_email'),
1103 1 # counter
1103 1 # counter
1104 ]
1104 ]
1105
1105
1106 else:
1106 else:
1107 # increase counter
1107 # increase counter
1108 unique[commit.author][2] += 1
1108 unique[commit.author][2] += 1
1109
1109
1110 c.authors = [val for val in unique.values()]
1110 c.authors = [val for val in unique.values()]
1111
1111
1112 return self._get_template_context(c)
1112 return self._get_template_context(c)
1113
1113
1114 @LoginRequired()
1114 @LoginRequired()
1115 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1115 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1116 @view_config(
1116 @view_config(
1117 route_name='repo_files_check_head', request_method='POST',
1118 renderer='json_ext', xhr=True)
1119 def repo_files_check_head(self):
1120 self.load_default_context()
1121
1122 commit_id, f_path = self._get_commit_and_path()
1123 _branch_name, _sha_commit_id, is_head = \
1124 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1125
1126 new_path = self.request.POST.get('path')
1127 operation = self.request.POST.get('operation')
1128 path_exist = ''
1129
1130 if new_path and operation in ['create', 'upload']:
1131 new_f_path = os.path.join(f_path.lstrip('/'), new_path)
1132 try:
1133 commit_obj = self.rhodecode_vcs_repo.get_commit(commit_id)
1134 # NOTE(dan): construct whole path without leading /
1135 file_node = commit_obj.get_node(new_f_path)
1136 if file_node is not None:
1137 path_exist = new_f_path
1138 except EmptyRepositoryError:
1139 pass
1140 except Exception:
1141 pass
1142
1143 return {
1144 'branch': _branch_name,
1145 'sha': _sha_commit_id,
1146 'is_head': is_head,
1147 'path_exists': path_exist
1148 }
1149
1150 @LoginRequired()
1151 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1152 @view_config(
1117 route_name='repo_files_remove_file', request_method='GET',
1153 route_name='repo_files_remove_file', request_method='GET',
1118 renderer='rhodecode:templates/files/files_delete.mako')
1154 renderer='rhodecode:templates/files/files_delete.mako')
1119 def repo_files_remove_file(self):
1155 def repo_files_remove_file(self):
1120 _ = self.request.translate
1156 _ = self.request.translate
1121 c = self.load_default_context()
1157 c = self.load_default_context()
1122 commit_id, f_path = self._get_commit_and_path()
1158 commit_id, f_path = self._get_commit_and_path()
1123
1159
1124 self._ensure_not_locked()
1160 self._ensure_not_locked()
1125 _branch_name, _sha_commit_id, is_head = \
1161 _branch_name, _sha_commit_id, is_head = \
1126 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1162 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1127
1163
1128 self.forbid_non_head(is_head, f_path)
1164 self.forbid_non_head(is_head, f_path)
1129 self.check_branch_permission(_branch_name)
1165 self.check_branch_permission(_branch_name)
1130
1166
1131 c.commit = self._get_commit_or_redirect(commit_id)
1167 c.commit = self._get_commit_or_redirect(commit_id)
1132 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1168 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1133
1169
1134 c.default_message = _(
1170 c.default_message = _(
1135 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1171 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1136 c.f_path = f_path
1172 c.f_path = f_path
1137
1173
1138 return self._get_template_context(c)
1174 return self._get_template_context(c)
1139
1175
1140 @LoginRequired()
1176 @LoginRequired()
1141 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1177 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1142 @CSRFRequired()
1178 @CSRFRequired()
1143 @view_config(
1179 @view_config(
1144 route_name='repo_files_delete_file', request_method='POST',
1180 route_name='repo_files_delete_file', request_method='POST',
1145 renderer=None)
1181 renderer=None)
1146 def repo_files_delete_file(self):
1182 def repo_files_delete_file(self):
1147 _ = self.request.translate
1183 _ = self.request.translate
1148
1184
1149 c = self.load_default_context()
1185 c = self.load_default_context()
1150 commit_id, f_path = self._get_commit_and_path()
1186 commit_id, f_path = self._get_commit_and_path()
1151
1187
1152 self._ensure_not_locked()
1188 self._ensure_not_locked()
1153 _branch_name, _sha_commit_id, is_head = \
1189 _branch_name, _sha_commit_id, is_head = \
1154 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1190 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1155
1191
1156 self.forbid_non_head(is_head, f_path)
1192 self.forbid_non_head(is_head, f_path)
1157 self.check_branch_permission(_branch_name)
1193 self.check_branch_permission(_branch_name)
1158
1194
1159 c.commit = self._get_commit_or_redirect(commit_id)
1195 c.commit = self._get_commit_or_redirect(commit_id)
1160 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1196 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1161
1197
1162 c.default_message = _(
1198 c.default_message = _(
1163 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1199 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1164 c.f_path = f_path
1200 c.f_path = f_path
1165 node_path = f_path
1201 node_path = f_path
1166 author = self._rhodecode_db_user.full_contact
1202 author = self._rhodecode_db_user.full_contact
1167 message = self.request.POST.get('message') or c.default_message
1203 message = self.request.POST.get('message') or c.default_message
1168 try:
1204 try:
1169 nodes = {
1205 nodes = {
1170 node_path: {
1206 node_path: {
1171 'content': ''
1207 'content': ''
1172 }
1208 }
1173 }
1209 }
1174 ScmModel().delete_nodes(
1210 ScmModel().delete_nodes(
1175 user=self._rhodecode_db_user.user_id, repo=self.db_repo,
1211 user=self._rhodecode_db_user.user_id, repo=self.db_repo,
1176 message=message,
1212 message=message,
1177 nodes=nodes,
1213 nodes=nodes,
1178 parent_commit=c.commit,
1214 parent_commit=c.commit,
1179 author=author,
1215 author=author,
1180 )
1216 )
1181
1217
1182 h.flash(
1218 h.flash(
1183 _('Successfully deleted file `{}`').format(
1219 _('Successfully deleted file `{}`').format(
1184 h.escape(f_path)), category='success')
1220 h.escape(f_path)), category='success')
1185 except Exception:
1221 except Exception:
1186 log.exception('Error during commit operation')
1222 log.exception('Error during commit operation')
1187 h.flash(_('Error occurred during commit'), category='error')
1223 h.flash(_('Error occurred during commit'), category='error')
1188 raise HTTPFound(
1224 raise HTTPFound(
1189 h.route_path('repo_commit', repo_name=self.db_repo_name,
1225 h.route_path('repo_commit', repo_name=self.db_repo_name,
1190 commit_id='tip'))
1226 commit_id='tip'))
1191
1227
1192 @LoginRequired()
1228 @LoginRequired()
1193 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1229 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1194 @view_config(
1230 @view_config(
1195 route_name='repo_files_edit_file', request_method='GET',
1231 route_name='repo_files_edit_file', request_method='GET',
1196 renderer='rhodecode:templates/files/files_edit.mako')
1232 renderer='rhodecode:templates/files/files_edit.mako')
1197 def repo_files_edit_file(self):
1233 def repo_files_edit_file(self):
1198 _ = self.request.translate
1234 _ = self.request.translate
1199 c = self.load_default_context()
1235 c = self.load_default_context()
1200 commit_id, f_path = self._get_commit_and_path()
1236 commit_id, f_path = self._get_commit_and_path()
1201
1237
1202 self._ensure_not_locked()
1238 self._ensure_not_locked()
1203 _branch_name, _sha_commit_id, is_head = \
1239 _branch_name, _sha_commit_id, is_head = \
1204 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1240 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1205
1241
1206 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1242 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1207 self.check_branch_permission(_branch_name, commit_id=commit_id)
1243 self.check_branch_permission(_branch_name, commit_id=commit_id)
1208
1244
1209 c.commit = self._get_commit_or_redirect(commit_id)
1245 c.commit = self._get_commit_or_redirect(commit_id)
1210 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1246 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1211
1247
1212 if c.file.is_binary:
1248 if c.file.is_binary:
1213 files_url = h.route_path(
1249 files_url = h.route_path(
1214 'repo_files',
1250 'repo_files',
1215 repo_name=self.db_repo_name,
1251 repo_name=self.db_repo_name,
1216 commit_id=c.commit.raw_id, f_path=f_path)
1252 commit_id=c.commit.raw_id, f_path=f_path)
1217 raise HTTPFound(files_url)
1253 raise HTTPFound(files_url)
1218
1254
1219 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1255 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1220 c.f_path = f_path
1256 c.f_path = f_path
1221
1257
1222 return self._get_template_context(c)
1258 return self._get_template_context(c)
1223
1259
1224 @LoginRequired()
1260 @LoginRequired()
1225 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1261 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1226 @CSRFRequired()
1262 @CSRFRequired()
1227 @view_config(
1263 @view_config(
1228 route_name='repo_files_update_file', request_method='POST',
1264 route_name='repo_files_update_file', request_method='POST',
1229 renderer=None)
1265 renderer=None)
1230 def repo_files_update_file(self):
1266 def repo_files_update_file(self):
1231 _ = self.request.translate
1267 _ = self.request.translate
1232 c = self.load_default_context()
1268 c = self.load_default_context()
1233 commit_id, f_path = self._get_commit_and_path()
1269 commit_id, f_path = self._get_commit_and_path()
1234
1270
1235 self._ensure_not_locked()
1271 self._ensure_not_locked()
1236
1272
1237 c.commit = self._get_commit_or_redirect(commit_id)
1273 c.commit = self._get_commit_or_redirect(commit_id)
1238 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1274 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1239
1275
1240 if c.file.is_binary:
1276 if c.file.is_binary:
1241 raise HTTPFound(h.route_path('repo_files', repo_name=self.db_repo_name,
1277 raise HTTPFound(h.route_path('repo_files', repo_name=self.db_repo_name,
1242 commit_id=c.commit.raw_id, f_path=f_path))
1278 commit_id=c.commit.raw_id, f_path=f_path))
1243
1279
1244 _branch_name, _sha_commit_id, is_head = \
1280 _branch_name, _sha_commit_id, is_head = \
1245 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1281 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1246
1282
1247 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1283 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1248 self.check_branch_permission(_branch_name, commit_id=commit_id)
1284 self.check_branch_permission(_branch_name, commit_id=commit_id)
1249
1285
1250 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1286 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1251 c.f_path = f_path
1287 c.f_path = f_path
1252
1288
1253 old_content = c.file.content
1289 old_content = c.file.content
1254 sl = old_content.splitlines(1)
1290 sl = old_content.splitlines(1)
1255 first_line = sl[0] if sl else ''
1291 first_line = sl[0] if sl else ''
1256
1292
1257 r_post = self.request.POST
1293 r_post = self.request.POST
1258 # line endings: 0 - Unix, 1 - Mac, 2 - DOS
1294 # line endings: 0 - Unix, 1 - Mac, 2 - DOS
1259 line_ending_mode = detect_mode(first_line, 0)
1295 line_ending_mode = detect_mode(first_line, 0)
1260 content = convert_line_endings(r_post.get('content', ''), line_ending_mode)
1296 content = convert_line_endings(r_post.get('content', ''), line_ending_mode)
1261
1297
1262 message = r_post.get('message') or c.default_message
1298 message = r_post.get('message') or c.default_message
1263 org_node_path = c.file.unicode_path
1299 org_node_path = c.file.unicode_path
1264 filename = r_post['filename']
1300 filename = r_post['filename']
1265
1301
1266 root_path = c.file.dir_path
1302 root_path = c.file.dir_path
1267 pure_path = self.create_pure_path(root_path, filename)
1303 pure_path = self.create_pure_path(root_path, filename)
1268 node_path = safe_unicode(bytes(pure_path))
1304 node_path = safe_unicode(bytes(pure_path))
1269
1305
1270 default_redirect_url = h.route_path('repo_commit', repo_name=self.db_repo_name,
1306 default_redirect_url = h.route_path('repo_commit', repo_name=self.db_repo_name,
1271 commit_id=commit_id)
1307 commit_id=commit_id)
1272 if content == old_content and node_path == org_node_path:
1308 if content == old_content and node_path == org_node_path:
1273 h.flash(_('No changes detected on {}').format(h.escape(org_node_path)),
1309 h.flash(_('No changes detected on {}').format(h.escape(org_node_path)),
1274 category='warning')
1310 category='warning')
1275 raise HTTPFound(default_redirect_url)
1311 raise HTTPFound(default_redirect_url)
1276
1312
1277 try:
1313 try:
1278 mapping = {
1314 mapping = {
1279 org_node_path: {
1315 org_node_path: {
1280 'org_filename': org_node_path,
1316 'org_filename': org_node_path,
1281 'filename': node_path,
1317 'filename': node_path,
1282 'content': content,
1318 'content': content,
1283 'lexer': '',
1319 'lexer': '',
1284 'op': 'mod',
1320 'op': 'mod',
1285 'mode': c.file.mode
1321 'mode': c.file.mode
1286 }
1322 }
1287 }
1323 }
1288
1324
1289 commit = ScmModel().update_nodes(
1325 commit = ScmModel().update_nodes(
1290 user=self._rhodecode_db_user.user_id,
1326 user=self._rhodecode_db_user.user_id,
1291 repo=self.db_repo,
1327 repo=self.db_repo,
1292 message=message,
1328 message=message,
1293 nodes=mapping,
1329 nodes=mapping,
1294 parent_commit=c.commit,
1330 parent_commit=c.commit,
1295 )
1331 )
1296
1332
1297 h.flash(_('Successfully committed changes to file `{}`').format(
1333 h.flash(_('Successfully committed changes to file `{}`').format(
1298 h.escape(f_path)), category='success')
1334 h.escape(f_path)), category='success')
1299 default_redirect_url = h.route_path(
1335 default_redirect_url = h.route_path(
1300 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1336 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1301
1337
1302 except Exception:
1338 except Exception:
1303 log.exception('Error occurred during commit')
1339 log.exception('Error occurred during commit')
1304 h.flash(_('Error occurred during commit'), category='error')
1340 h.flash(_('Error occurred during commit'), category='error')
1305
1341
1306 raise HTTPFound(default_redirect_url)
1342 raise HTTPFound(default_redirect_url)
1307
1343
1308 @LoginRequired()
1344 @LoginRequired()
1309 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1345 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1310 @view_config(
1346 @view_config(
1311 route_name='repo_files_add_file', request_method='GET',
1347 route_name='repo_files_add_file', request_method='GET',
1312 renderer='rhodecode:templates/files/files_add.mako')
1348 renderer='rhodecode:templates/files/files_add.mako')
1313 @view_config(
1349 @view_config(
1314 route_name='repo_files_upload_file', request_method='GET',
1350 route_name='repo_files_upload_file', request_method='GET',
1315 renderer='rhodecode:templates/files/files_upload.mako')
1351 renderer='rhodecode:templates/files/files_upload.mako')
1316 def repo_files_add_file(self):
1352 def repo_files_add_file(self):
1317 _ = self.request.translate
1353 _ = self.request.translate
1318 c = self.load_default_context()
1354 c = self.load_default_context()
1319 commit_id, f_path = self._get_commit_and_path()
1355 commit_id, f_path = self._get_commit_and_path()
1320
1356
1321 self._ensure_not_locked()
1357 self._ensure_not_locked()
1322
1358
1323 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1359 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1324 if c.commit is None:
1360 if c.commit is None:
1325 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1361 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1326
1362
1327 if self.rhodecode_vcs_repo.is_empty():
1363 if self.rhodecode_vcs_repo.is_empty():
1328 # for empty repository we cannot check for current branch, we rely on
1364 # for empty repository we cannot check for current branch, we rely on
1329 # c.commit.branch instead
1365 # c.commit.branch instead
1330 _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True
1366 _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True
1331 else:
1367 else:
1332 _branch_name, _sha_commit_id, is_head = \
1368 _branch_name, _sha_commit_id, is_head = \
1333 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1369 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1334
1370
1335 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1371 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1336 self.check_branch_permission(_branch_name, commit_id=commit_id)
1372 self.check_branch_permission(_branch_name, commit_id=commit_id)
1337
1373
1338 c.default_message = (_('Added file via RhodeCode Enterprise'))
1374 c.default_message = (_('Added file via RhodeCode Enterprise'))
1339 c.f_path = f_path.lstrip('/') # ensure not relative path
1375 c.f_path = f_path.lstrip('/') # ensure not relative path
1340
1376
1341 return self._get_template_context(c)
1377 return self._get_template_context(c)
1342
1378
1343 @LoginRequired()
1379 @LoginRequired()
1344 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1380 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1345 @CSRFRequired()
1381 @CSRFRequired()
1346 @view_config(
1382 @view_config(
1347 route_name='repo_files_create_file', request_method='POST',
1383 route_name='repo_files_create_file', request_method='POST',
1348 renderer=None)
1384 renderer=None)
1349 def repo_files_create_file(self):
1385 def repo_files_create_file(self):
1350 _ = self.request.translate
1386 _ = self.request.translate
1351 c = self.load_default_context()
1387 c = self.load_default_context()
1352 commit_id, f_path = self._get_commit_and_path()
1388 commit_id, f_path = self._get_commit_and_path()
1353
1389
1354 self._ensure_not_locked()
1390 self._ensure_not_locked()
1355
1391
1356 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1392 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1357 if c.commit is None:
1393 if c.commit is None:
1358 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1394 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1359
1395
1360 # calculate redirect URL
1396 # calculate redirect URL
1361 if self.rhodecode_vcs_repo.is_empty():
1397 if self.rhodecode_vcs_repo.is_empty():
1362 default_redirect_url = h.route_path(
1398 default_redirect_url = h.route_path(
1363 'repo_summary', repo_name=self.db_repo_name)
1399 'repo_summary', repo_name=self.db_repo_name)
1364 else:
1400 else:
1365 default_redirect_url = h.route_path(
1401 default_redirect_url = h.route_path(
1366 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1402 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1367
1403
1368 if self.rhodecode_vcs_repo.is_empty():
1404 if self.rhodecode_vcs_repo.is_empty():
1369 # for empty repository we cannot check for current branch, we rely on
1405 # for empty repository we cannot check for current branch, we rely on
1370 # c.commit.branch instead
1406 # c.commit.branch instead
1371 _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True
1407 _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True
1372 else:
1408 else:
1373 _branch_name, _sha_commit_id, is_head = \
1409 _branch_name, _sha_commit_id, is_head = \
1374 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1410 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1375
1411
1376 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1412 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1377 self.check_branch_permission(_branch_name, commit_id=commit_id)
1413 self.check_branch_permission(_branch_name, commit_id=commit_id)
1378
1414
1379 c.default_message = (_('Added file via RhodeCode Enterprise'))
1415 c.default_message = (_('Added file via RhodeCode Enterprise'))
1380 c.f_path = f_path
1416 c.f_path = f_path
1381
1417
1382 r_post = self.request.POST
1418 r_post = self.request.POST
1383 message = r_post.get('message') or c.default_message
1419 message = r_post.get('message') or c.default_message
1384 filename = r_post.get('filename')
1420 filename = r_post.get('filename')
1385 unix_mode = 0
1421 unix_mode = 0
1386 content = convert_line_endings(r_post.get('content', ''), unix_mode)
1422 content = convert_line_endings(r_post.get('content', ''), unix_mode)
1387
1423
1388 if not filename:
1424 if not filename:
1389 # If there's no commit, redirect to repo summary
1425 # If there's no commit, redirect to repo summary
1390 if type(c.commit) is EmptyCommit:
1426 if type(c.commit) is EmptyCommit:
1391 redirect_url = h.route_path(
1427 redirect_url = h.route_path(
1392 'repo_summary', repo_name=self.db_repo_name)
1428 'repo_summary', repo_name=self.db_repo_name)
1393 else:
1429 else:
1394 redirect_url = default_redirect_url
1430 redirect_url = default_redirect_url
1395 h.flash(_('No filename specified'), category='warning')
1431 h.flash(_('No filename specified'), category='warning')
1396 raise HTTPFound(redirect_url)
1432 raise HTTPFound(redirect_url)
1397
1433
1398 root_path = f_path
1434 root_path = f_path
1399 pure_path = self.create_pure_path(root_path, filename)
1435 pure_path = self.create_pure_path(root_path, filename)
1400 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1436 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1401
1437
1402 author = self._rhodecode_db_user.full_contact
1438 author = self._rhodecode_db_user.full_contact
1403 nodes = {
1439 nodes = {
1404 node_path: {
1440 node_path: {
1405 'content': content
1441 'content': content
1406 }
1442 }
1407 }
1443 }
1408
1444
1409 try:
1445 try:
1410
1446
1411 commit = ScmModel().create_nodes(
1447 commit = ScmModel().create_nodes(
1412 user=self._rhodecode_db_user.user_id,
1448 user=self._rhodecode_db_user.user_id,
1413 repo=self.db_repo,
1449 repo=self.db_repo,
1414 message=message,
1450 message=message,
1415 nodes=nodes,
1451 nodes=nodes,
1416 parent_commit=c.commit,
1452 parent_commit=c.commit,
1417 author=author,
1453 author=author,
1418 )
1454 )
1419
1455
1420 h.flash(_('Successfully committed new file `{}`').format(
1456 h.flash(_('Successfully committed new file `{}`').format(
1421 h.escape(node_path)), category='success')
1457 h.escape(node_path)), category='success')
1422
1458
1423 default_redirect_url = h.route_path(
1459 default_redirect_url = h.route_path(
1424 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1460 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1425
1461
1426 except NonRelativePathError:
1462 except NonRelativePathError:
1427 log.exception('Non Relative path found')
1463 log.exception('Non Relative path found')
1428 h.flash(_('The location specified must be a relative path and must not '
1464 h.flash(_('The location specified must be a relative path and must not '
1429 'contain .. in the path'), category='warning')
1465 'contain .. in the path'), category='warning')
1430 raise HTTPFound(default_redirect_url)
1466 raise HTTPFound(default_redirect_url)
1431 except (NodeError, NodeAlreadyExistsError) as e:
1467 except (NodeError, NodeAlreadyExistsError) as e:
1432 h.flash(_(h.escape(e)), category='error')
1468 h.flash(_(h.escape(e)), category='error')
1433 except Exception:
1469 except Exception:
1434 log.exception('Error occurred during commit')
1470 log.exception('Error occurred during commit')
1435 h.flash(_('Error occurred during commit'), category='error')
1471 h.flash(_('Error occurred during commit'), category='error')
1436
1472
1437 raise HTTPFound(default_redirect_url)
1473 raise HTTPFound(default_redirect_url)
1438
1474
1439 @LoginRequired()
1475 @LoginRequired()
1440 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1476 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1441 @CSRFRequired()
1477 @CSRFRequired()
1442 @view_config(
1478 @view_config(
1443 route_name='repo_files_upload_file', request_method='POST',
1479 route_name='repo_files_upload_file', request_method='POST',
1444 renderer='json_ext')
1480 renderer='json_ext')
1445 def repo_files_upload_file(self):
1481 def repo_files_upload_file(self):
1446 _ = self.request.translate
1482 _ = self.request.translate
1447 c = self.load_default_context()
1483 c = self.load_default_context()
1448 commit_id, f_path = self._get_commit_and_path()
1484 commit_id, f_path = self._get_commit_and_path()
1449
1485
1450 self._ensure_not_locked()
1486 self._ensure_not_locked()
1451
1487
1452 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1488 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1453 if c.commit is None:
1489 if c.commit is None:
1454 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1490 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1455
1491
1456 # calculate redirect URL
1492 # calculate redirect URL
1457 if self.rhodecode_vcs_repo.is_empty():
1493 if self.rhodecode_vcs_repo.is_empty():
1458 default_redirect_url = h.route_path(
1494 default_redirect_url = h.route_path(
1459 'repo_summary', repo_name=self.db_repo_name)
1495 'repo_summary', repo_name=self.db_repo_name)
1460 else:
1496 else:
1461 default_redirect_url = h.route_path(
1497 default_redirect_url = h.route_path(
1462 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1498 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1463
1499
1464 if self.rhodecode_vcs_repo.is_empty():
1500 if self.rhodecode_vcs_repo.is_empty():
1465 # for empty repository we cannot check for current branch, we rely on
1501 # for empty repository we cannot check for current branch, we rely on
1466 # c.commit.branch instead
1502 # c.commit.branch instead
1467 _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True
1503 _branch_name, _sha_commit_id, is_head = c.commit.branch, '', True
1468 else:
1504 else:
1469 _branch_name, _sha_commit_id, is_head = \
1505 _branch_name, _sha_commit_id, is_head = \
1470 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1506 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1471
1507
1472 error = self.forbid_non_head(is_head, f_path, json_mode=True)
1508 error = self.forbid_non_head(is_head, f_path, json_mode=True)
1473 if error:
1509 if error:
1474 return {
1510 return {
1475 'error': error,
1511 'error': error,
1476 'redirect_url': default_redirect_url
1512 'redirect_url': default_redirect_url
1477 }
1513 }
1478 error = self.check_branch_permission(_branch_name, json_mode=True)
1514 error = self.check_branch_permission(_branch_name, json_mode=True)
1479 if error:
1515 if error:
1480 return {
1516 return {
1481 'error': error,
1517 'error': error,
1482 'redirect_url': default_redirect_url
1518 'redirect_url': default_redirect_url
1483 }
1519 }
1484
1520
1485 c.default_message = (_('Uploaded file via RhodeCode Enterprise'))
1521 c.default_message = (_('Uploaded file via RhodeCode Enterprise'))
1486 c.f_path = f_path
1522 c.f_path = f_path
1487
1523
1488 r_post = self.request.POST
1524 r_post = self.request.POST
1489
1525
1490 message = c.default_message
1526 message = c.default_message
1491 user_message = r_post.getall('message')
1527 user_message = r_post.getall('message')
1492 if isinstance(user_message, list) and user_message:
1528 if isinstance(user_message, list) and user_message:
1493 # we take the first from duplicated results if it's not empty
1529 # we take the first from duplicated results if it's not empty
1494 message = user_message[0] if user_message[0] else message
1530 message = user_message[0] if user_message[0] else message
1495
1531
1496 nodes = {}
1532 nodes = {}
1497
1533
1498 for file_obj in r_post.getall('files_upload') or []:
1534 for file_obj in r_post.getall('files_upload') or []:
1499 content = file_obj.file
1535 content = file_obj.file
1500 filename = file_obj.filename
1536 filename = file_obj.filename
1501
1537
1502 root_path = f_path
1538 root_path = f_path
1503 pure_path = self.create_pure_path(root_path, filename)
1539 pure_path = self.create_pure_path(root_path, filename)
1504 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1540 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1505
1541
1506 nodes[node_path] = {
1542 nodes[node_path] = {
1507 'content': content
1543 'content': content
1508 }
1544 }
1509
1545
1510 if not nodes:
1546 if not nodes:
1511 error = 'missing files'
1547 error = 'missing files'
1512 return {
1548 return {
1513 'error': error,
1549 'error': error,
1514 'redirect_url': default_redirect_url
1550 'redirect_url': default_redirect_url
1515 }
1551 }
1516
1552
1517 author = self._rhodecode_db_user.full_contact
1553 author = self._rhodecode_db_user.full_contact
1518
1554
1519 try:
1555 try:
1520 commit = ScmModel().create_nodes(
1556 commit = ScmModel().create_nodes(
1521 user=self._rhodecode_db_user.user_id,
1557 user=self._rhodecode_db_user.user_id,
1522 repo=self.db_repo,
1558 repo=self.db_repo,
1523 message=message,
1559 message=message,
1524 nodes=nodes,
1560 nodes=nodes,
1525 parent_commit=c.commit,
1561 parent_commit=c.commit,
1526 author=author,
1562 author=author,
1527 )
1563 )
1528 if len(nodes) == 1:
1564 if len(nodes) == 1:
1529 flash_message = _('Successfully committed {} new files').format(len(nodes))
1565 flash_message = _('Successfully committed {} new files').format(len(nodes))
1530 else:
1566 else:
1531 flash_message = _('Successfully committed 1 new file')
1567 flash_message = _('Successfully committed 1 new file')
1532
1568
1533 h.flash(flash_message, category='success')
1569 h.flash(flash_message, category='success')
1534
1570
1535 default_redirect_url = h.route_path(
1571 default_redirect_url = h.route_path(
1536 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1572 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1537
1573
1538 except NonRelativePathError:
1574 except NonRelativePathError:
1539 log.exception('Non Relative path found')
1575 log.exception('Non Relative path found')
1540 error = _('The location specified must be a relative path and must not '
1576 error = _('The location specified must be a relative path and must not '
1541 'contain .. in the path')
1577 'contain .. in the path')
1542 h.flash(error, category='warning')
1578 h.flash(error, category='warning')
1543
1579
1544 return {
1580 return {
1545 'error': error,
1581 'error': error,
1546 'redirect_url': default_redirect_url
1582 'redirect_url': default_redirect_url
1547 }
1583 }
1548 except (NodeError, NodeAlreadyExistsError) as e:
1584 except (NodeError, NodeAlreadyExistsError) as e:
1549 error = h.escape(e)
1585 error = h.escape(e)
1550 h.flash(error, category='error')
1586 h.flash(error, category='error')
1551
1587
1552 return {
1588 return {
1553 'error': error,
1589 'error': error,
1554 'redirect_url': default_redirect_url
1590 'redirect_url': default_redirect_url
1555 }
1591 }
1556 except Exception:
1592 except Exception:
1557 log.exception('Error occurred during commit')
1593 log.exception('Error occurred during commit')
1558 error = _('Error occurred during commit')
1594 error = _('Error occurred during commit')
1559 h.flash(error, category='error')
1595 h.flash(error, category='error')
1560 return {
1596 return {
1561 'error': error,
1597 'error': error,
1562 'redirect_url': default_redirect_url
1598 'redirect_url': default_redirect_url
1563 }
1599 }
1564
1600
1565 return {
1601 return {
1566 'error': None,
1602 'error': None,
1567 'redirect_url': default_redirect_url
1603 'redirect_url': default_redirect_url
1568 }
1604 }
@@ -1,3054 +1,3058 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 'variables';
8 @import 'variables';
9 @import 'bootstrap-variables';
9 @import 'bootstrap-variables';
10 @import 'form-bootstrap';
10 @import 'form-bootstrap';
11 @import 'codemirror';
11 @import 'codemirror';
12 @import 'legacy_code_styles';
12 @import 'legacy_code_styles';
13 @import 'readme-box';
13 @import 'readme-box';
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 @import 'tooltips';
29 @import 'tooltips';
30
30
31 //--- BASE ------------------//
31 //--- BASE ------------------//
32 .noscript-error {
32 .noscript-error {
33 top: 0;
33 top: 0;
34 left: 0;
34 left: 0;
35 width: 100%;
35 width: 100%;
36 z-index: 101;
36 z-index: 101;
37 text-align: center;
37 text-align: center;
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 font-weight: @text-semibold-weight;
42 font-weight: @text-semibold-weight;
43 font-family: @text-semibold;
43 font-family: @text-semibold;
44 }
44 }
45
45
46 html {
46 html {
47 display: table;
47 display: table;
48 height: 100%;
48 height: 100%;
49 width: 100%;
49 width: 100%;
50 }
50 }
51
51
52 body {
52 body {
53 display: table-cell;
53 display: table-cell;
54 width: 100%;
54 width: 100%;
55 }
55 }
56
56
57 //--- LAYOUT ------------------//
57 //--- LAYOUT ------------------//
58
58
59 .hidden{
59 .hidden{
60 display: none !important;
60 display: none !important;
61 }
61 }
62
62
63 .box{
63 .box{
64 float: left;
64 float: left;
65 width: 100%;
65 width: 100%;
66 }
66 }
67
67
68 .browser-header {
68 .browser-header {
69 clear: both;
69 clear: both;
70 }
70 }
71 .main {
71 .main {
72 clear: both;
72 clear: both;
73 padding:0 0 @pagepadding;
73 padding:0 0 @pagepadding;
74 height: auto;
74 height: auto;
75
75
76 &:after { //clearfix
76 &:after { //clearfix
77 content:"";
77 content:"";
78 clear:both;
78 clear:both;
79 width:100%;
79 width:100%;
80 display:block;
80 display:block;
81 }
81 }
82 }
82 }
83
83
84 .action-link{
84 .action-link{
85 margin-left: @padding;
85 margin-left: @padding;
86 padding-left: @padding;
86 padding-left: @padding;
87 border-left: @border-thickness solid @border-default-color;
87 border-left: @border-thickness solid @border-default-color;
88 }
88 }
89
89
90 .cursor-pointer {
90 .cursor-pointer {
91 cursor: pointer;
91 cursor: pointer;
92 }
92 }
93
93
94 input + .action-link, .action-link.first{
94 input + .action-link, .action-link.first{
95 border-left: none;
95 border-left: none;
96 }
96 }
97
97
98 .action-link.last{
98 .action-link.last{
99 margin-right: @padding;
99 margin-right: @padding;
100 padding-right: @padding;
100 padding-right: @padding;
101 }
101 }
102
102
103 .action-link.active,
103 .action-link.active,
104 .action-link.active a{
104 .action-link.active a{
105 color: @grey4;
105 color: @grey4;
106 }
106 }
107
107
108 .action-link.disabled {
108 .action-link.disabled {
109 color: @grey4;
109 color: @grey4;
110 cursor: inherit;
110 cursor: inherit;
111 }
111 }
112
112
113
113
114 .clipboard-action {
114 .clipboard-action {
115 cursor: pointer;
115 cursor: pointer;
116 margin-left: 5px;
116 margin-left: 5px;
117
117
118 &:not(.no-grey) {
118 &:not(.no-grey) {
119
119
120 &:hover {
120 &:hover {
121 color: @grey2;
121 color: @grey2;
122 }
122 }
123 color: @grey4;
123 color: @grey4;
124 }
124 }
125 }
125 }
126
126
127 ul.simple-list{
127 ul.simple-list{
128 list-style: none;
128 list-style: none;
129 margin: 0;
129 margin: 0;
130 padding: 0;
130 padding: 0;
131 }
131 }
132
132
133 .main-content {
133 .main-content {
134 padding-bottom: @pagepadding;
134 padding-bottom: @pagepadding;
135 }
135 }
136
136
137 .wide-mode-wrapper {
137 .wide-mode-wrapper {
138 max-width:4000px !important;
138 max-width:4000px !important;
139 }
139 }
140
140
141 .wrapper {
141 .wrapper {
142 position: relative;
142 position: relative;
143 max-width: @wrapper-maxwidth;
143 max-width: @wrapper-maxwidth;
144 margin: 0 auto;
144 margin: 0 auto;
145 }
145 }
146
146
147 #content {
147 #content {
148 clear: both;
148 clear: both;
149 padding: 0 @contentpadding;
149 padding: 0 @contentpadding;
150 }
150 }
151
151
152 .advanced-settings-fields{
152 .advanced-settings-fields{
153 input{
153 input{
154 margin-left: @textmargin;
154 margin-left: @textmargin;
155 margin-right: @padding/2;
155 margin-right: @padding/2;
156 }
156 }
157 }
157 }
158
158
159 .cs_files_title {
159 .cs_files_title {
160 margin: @pagepadding 0 0;
160 margin: @pagepadding 0 0;
161 }
161 }
162
162
163 input.inline[type="file"] {
163 input.inline[type="file"] {
164 display: inline;
164 display: inline;
165 }
165 }
166
166
167 .error_page {
167 .error_page {
168 margin: 10% auto;
168 margin: 10% auto;
169
169
170 h1 {
170 h1 {
171 color: @grey2;
171 color: @grey2;
172 }
172 }
173
173
174 .alert {
174 .alert {
175 margin: @padding 0;
175 margin: @padding 0;
176 }
176 }
177
177
178 .error-branding {
178 .error-branding {
179 color: @grey4;
179 color: @grey4;
180 font-weight: @text-semibold-weight;
180 font-weight: @text-semibold-weight;
181 font-family: @text-semibold;
181 font-family: @text-semibold;
182 }
182 }
183
183
184 .error_message {
184 .error_message {
185 font-family: @text-regular;
185 font-family: @text-regular;
186 }
186 }
187
187
188 .sidebar {
188 .sidebar {
189 min-height: 275px;
189 min-height: 275px;
190 margin: 0;
190 margin: 0;
191 padding: 0 0 @sidebarpadding @sidebarpadding;
191 padding: 0 0 @sidebarpadding @sidebarpadding;
192 border: none;
192 border: none;
193 }
193 }
194
194
195 .main-content {
195 .main-content {
196 position: relative;
196 position: relative;
197 margin: 0 @sidebarpadding @sidebarpadding;
197 margin: 0 @sidebarpadding @sidebarpadding;
198 padding: 0 0 0 @sidebarpadding;
198 padding: 0 0 0 @sidebarpadding;
199 border-left: @border-thickness solid @grey5;
199 border-left: @border-thickness solid @grey5;
200
200
201 @media (max-width:767px) {
201 @media (max-width:767px) {
202 clear: both;
202 clear: both;
203 width: 100%;
203 width: 100%;
204 margin: 0;
204 margin: 0;
205 border: none;
205 border: none;
206 }
206 }
207 }
207 }
208
208
209 .inner-column {
209 .inner-column {
210 float: left;
210 float: left;
211 width: 29.75%;
211 width: 29.75%;
212 min-height: 150px;
212 min-height: 150px;
213 margin: @sidebarpadding 2% 0 0;
213 margin: @sidebarpadding 2% 0 0;
214 padding: 0 2% 0 0;
214 padding: 0 2% 0 0;
215 border-right: @border-thickness solid @grey5;
215 border-right: @border-thickness solid @grey5;
216
216
217 @media (max-width:767px) {
217 @media (max-width:767px) {
218 clear: both;
218 clear: both;
219 width: 100%;
219 width: 100%;
220 border: none;
220 border: none;
221 }
221 }
222
222
223 ul {
223 ul {
224 padding-left: 1.25em;
224 padding-left: 1.25em;
225 }
225 }
226
226
227 &:last-child {
227 &:last-child {
228 margin: @sidebarpadding 0 0;
228 margin: @sidebarpadding 0 0;
229 border: none;
229 border: none;
230 }
230 }
231
231
232 h4 {
232 h4 {
233 margin: 0 0 @padding;
233 margin: 0 0 @padding;
234 font-weight: @text-semibold-weight;
234 font-weight: @text-semibold-weight;
235 font-family: @text-semibold;
235 font-family: @text-semibold;
236 }
236 }
237 }
237 }
238 }
238 }
239 .error-page-logo {
239 .error-page-logo {
240 width: 130px;
240 width: 130px;
241 height: 160px;
241 height: 160px;
242 }
242 }
243
243
244 // HEADER
244 // HEADER
245 .header {
245 .header {
246
246
247 // TODO: johbo: Fix login pages, so that they work without a min-height
247 // TODO: johbo: Fix login pages, so that they work without a min-height
248 // for the header and then remove the min-height. I chose a smaller value
248 // for the header and then remove the min-height. I chose a smaller value
249 // intentionally here to avoid rendering issues in the main navigation.
249 // intentionally here to avoid rendering issues in the main navigation.
250 min-height: 49px;
250 min-height: 49px;
251 min-width: 1024px;
251 min-width: 1024px;
252
252
253 position: relative;
253 position: relative;
254 vertical-align: bottom;
254 vertical-align: bottom;
255 padding: 0 @header-padding;
255 padding: 0 @header-padding;
256 background-color: @grey1;
256 background-color: @grey1;
257 color: @grey5;
257 color: @grey5;
258
258
259 .title {
259 .title {
260 overflow: visible;
260 overflow: visible;
261 }
261 }
262
262
263 &:before,
263 &:before,
264 &:after {
264 &:after {
265 content: "";
265 content: "";
266 clear: both;
266 clear: both;
267 width: 100%;
267 width: 100%;
268 }
268 }
269
269
270 // TODO: johbo: Avoids breaking "Repositories" chooser
270 // TODO: johbo: Avoids breaking "Repositories" chooser
271 .select2-container .select2-choice .select2-arrow {
271 .select2-container .select2-choice .select2-arrow {
272 display: none;
272 display: none;
273 }
273 }
274 }
274 }
275
275
276 #header-inner {
276 #header-inner {
277 &.title {
277 &.title {
278 margin: 0;
278 margin: 0;
279 }
279 }
280 &:before,
280 &:before,
281 &:after {
281 &:after {
282 content: "";
282 content: "";
283 clear: both;
283 clear: both;
284 }
284 }
285 }
285 }
286
286
287 // Gists
287 // Gists
288 #files_data {
288 #files_data {
289 clear: both; //for firefox
289 clear: both; //for firefox
290 padding-top: 10px;
290 padding-top: 10px;
291 }
291 }
292
292
293 #gistid {
293 #gistid {
294 margin-right: @padding;
294 margin-right: @padding;
295 }
295 }
296
296
297 // Global Settings Editor
297 // Global Settings Editor
298 .textarea.editor {
298 .textarea.editor {
299 float: left;
299 float: left;
300 position: relative;
300 position: relative;
301 max-width: @texteditor-width;
301 max-width: @texteditor-width;
302
302
303 select {
303 select {
304 position: absolute;
304 position: absolute;
305 top:10px;
305 top:10px;
306 right:0;
306 right:0;
307 }
307 }
308
308
309 .CodeMirror {
309 .CodeMirror {
310 margin: 0;
310 margin: 0;
311 }
311 }
312
312
313 .help-block {
313 .help-block {
314 margin: 0 0 @padding;
314 margin: 0 0 @padding;
315 padding:.5em;
315 padding:.5em;
316 background-color: @grey6;
316 background-color: @grey6;
317 &.pre-formatting {
317 &.pre-formatting {
318 white-space: pre;
318 white-space: pre;
319 }
319 }
320 }
320 }
321 }
321 }
322
322
323 ul.auth_plugins {
323 ul.auth_plugins {
324 margin: @padding 0 @padding @legend-width;
324 margin: @padding 0 @padding @legend-width;
325 padding: 0;
325 padding: 0;
326
326
327 li {
327 li {
328 margin-bottom: @padding;
328 margin-bottom: @padding;
329 line-height: 1em;
329 line-height: 1em;
330 list-style-type: none;
330 list-style-type: none;
331
331
332 .auth_buttons .btn {
332 .auth_buttons .btn {
333 margin-right: @padding;
333 margin-right: @padding;
334 }
334 }
335
335
336 }
336 }
337 }
337 }
338
338
339
339
340 // My Account PR list
340 // My Account PR list
341
341
342 #show_closed {
342 #show_closed {
343 margin: 0 1em 0 0;
343 margin: 0 1em 0 0;
344 }
344 }
345
345
346 #pull_request_list_table {
346 #pull_request_list_table {
347 .closed {
347 .closed {
348 background-color: @grey6;
348 background-color: @grey6;
349 }
349 }
350
350
351 .state-creating,
351 .state-creating,
352 .state-updating,
352 .state-updating,
353 .state-merging
353 .state-merging
354 {
354 {
355 background-color: @grey6;
355 background-color: @grey6;
356 }
356 }
357
357
358 .td-status {
358 .td-status {
359 padding-left: .5em;
359 padding-left: .5em;
360 }
360 }
361 .log-container .truncate {
361 .log-container .truncate {
362 height: 2.75em;
362 height: 2.75em;
363 white-space: pre-line;
363 white-space: pre-line;
364 }
364 }
365 table.rctable .user {
365 table.rctable .user {
366 padding-left: 0;
366 padding-left: 0;
367 }
367 }
368 table.rctable {
368 table.rctable {
369 td.td-description,
369 td.td-description,
370 .rc-user {
370 .rc-user {
371 min-width: auto;
371 min-width: auto;
372 }
372 }
373 }
373 }
374 }
374 }
375
375
376 // Pull Requests
376 // Pull Requests
377
377
378 .pullrequests_section_head {
378 .pullrequests_section_head {
379 display: block;
379 display: block;
380 clear: both;
380 clear: both;
381 margin: @padding 0;
381 margin: @padding 0;
382 font-weight: @text-bold-weight;
382 font-weight: @text-bold-weight;
383 font-family: @text-bold;
383 font-family: @text-bold;
384 }
384 }
385
385
386 .pr-commit-flow {
386 .pr-commit-flow {
387 position: relative;
387 position: relative;
388 font-weight: 600;
388 font-weight: 600;
389
389
390 .tag {
390 .tag {
391 display: inline-block;
391 display: inline-block;
392 margin: 0 1em .5em 0;
392 margin: 0 1em .5em 0;
393 }
393 }
394
394
395 .clone-url {
395 .clone-url {
396 display: inline-block;
396 display: inline-block;
397 margin: 0 0 .5em 0;
397 margin: 0 0 .5em 0;
398 padding: 0;
398 padding: 0;
399 line-height: 1.2em;
399 line-height: 1.2em;
400 }
400 }
401 }
401 }
402
402
403 .pr-mergeinfo {
403 .pr-mergeinfo {
404 min-width: 95% !important;
404 min-width: 95% !important;
405 padding: 0 !important;
405 padding: 0 !important;
406 border: 0;
406 border: 0;
407 }
407 }
408 .pr-mergeinfo-copy {
408 .pr-mergeinfo-copy {
409 padding: 0 0;
409 padding: 0 0;
410 }
410 }
411
411
412 .pr-pullinfo {
412 .pr-pullinfo {
413 min-width: 95% !important;
413 min-width: 95% !important;
414 padding: 0 !important;
414 padding: 0 !important;
415 border: 0;
415 border: 0;
416 }
416 }
417 .pr-pullinfo-copy {
417 .pr-pullinfo-copy {
418 padding: 0 0;
418 padding: 0 0;
419 }
419 }
420
420
421 .pr-title-input {
421 .pr-title-input {
422 width: 100%;
422 width: 100%;
423 font-size: 18px;
423 font-size: 18px;
424 margin: 0 0 4px 0;
424 margin: 0 0 4px 0;
425 padding: 0;
425 padding: 0;
426 line-height: 1.7em;
426 line-height: 1.7em;
427 color: @text-color;
427 color: @text-color;
428 letter-spacing: .02em;
428 letter-spacing: .02em;
429 font-weight: @text-bold-weight;
429 font-weight: @text-bold-weight;
430 font-family: @text-bold;
430 font-family: @text-bold;
431
431
432 &:hover {
432 &:hover {
433 box-shadow: none;
433 box-shadow: none;
434 }
434 }
435 }
435 }
436
436
437 #pr-title {
437 #pr-title {
438 input {
438 input {
439 border: 1px transparent;
439 border: 1px transparent;
440 color: black;
440 color: black;
441 opacity: 1;
441 opacity: 1;
442 background: #fff;
442 background: #fff;
443 font-size: 18px;
443 font-size: 18px;
444 }
444 }
445 }
445 }
446
446
447 .pr-title-closed-tag {
447 .pr-title-closed-tag {
448 font-size: 16px;
448 font-size: 16px;
449 }
449 }
450
450
451 #pr-desc {
451 #pr-desc {
452 padding: 10px 0;
452 padding: 10px 0;
453
453
454 .markdown-block {
454 .markdown-block {
455 padding: 0;
455 padding: 0;
456 margin-bottom: -30px;
456 margin-bottom: -30px;
457 }
457 }
458 }
458 }
459
459
460 #pullrequest_title {
460 #pullrequest_title {
461 width: 100%;
461 width: 100%;
462 box-sizing: border-box;
462 box-sizing: border-box;
463 }
463 }
464
464
465 #pr_open_message {
465 #pr_open_message {
466 border: @border-thickness solid #fff;
466 border: @border-thickness solid #fff;
467 border-radius: @border-radius;
467 border-radius: @border-radius;
468 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
468 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
469 text-align: left;
469 text-align: left;
470 overflow: hidden;
470 overflow: hidden;
471 }
471 }
472
472
473 .pr-details-title {
473 .pr-details-title {
474 height: 16px
474 height: 16px
475 }
475 }
476
476
477 .pr-details-title-author-pref {
477 .pr-details-title-author-pref {
478 padding-right: 10px
478 padding-right: 10px
479 }
479 }
480
480
481 .label-pr-detail {
481 .label-pr-detail {
482 display: table-cell;
482 display: table-cell;
483 width: 120px;
483 width: 120px;
484 padding-top: 7.5px;
484 padding-top: 7.5px;
485 padding-bottom: 7.5px;
485 padding-bottom: 7.5px;
486 padding-right: 7.5px;
486 padding-right: 7.5px;
487 }
487 }
488
488
489 .source-details ul {
489 .source-details ul {
490 padding: 10px 16px;
490 padding: 10px 16px;
491 }
491 }
492
492
493 .source-details-action {
493 .source-details-action {
494 color: @grey4;
494 color: @grey4;
495 font-size: 11px
495 font-size: 11px
496 }
496 }
497
497
498 .pr-submit-button {
498 .pr-submit-button {
499 float: right;
499 float: right;
500 margin: 0 0 0 5px;
500 margin: 0 0 0 5px;
501 }
501 }
502
502
503 .pr-spacing-container {
503 .pr-spacing-container {
504 padding: 20px;
504 padding: 20px;
505 clear: both
505 clear: both
506 }
506 }
507
507
508 #pr-description-input {
508 #pr-description-input {
509 margin-bottom: 0;
509 margin-bottom: 0;
510 }
510 }
511
511
512 .pr-description-label {
512 .pr-description-label {
513 vertical-align: top;
513 vertical-align: top;
514 }
514 }
515
515
516 #open_edit_pullrequest {
516 #open_edit_pullrequest {
517 padding: 0;
517 padding: 0;
518 }
518 }
519
519
520 #close_edit_pullrequest {
520 #close_edit_pullrequest {
521
521
522 }
522 }
523
523
524 #delete_pullrequest {
524 #delete_pullrequest {
525 clear: inherit;
525 clear: inherit;
526
526
527 form {
527 form {
528 display: inline;
528 display: inline;
529 }
529 }
530
530
531 }
531 }
532
532
533 .perms_section_head {
533 .perms_section_head {
534 min-width: 625px;
534 min-width: 625px;
535
535
536 h2 {
536 h2 {
537 margin-bottom: 0;
537 margin-bottom: 0;
538 }
538 }
539
539
540 .label-checkbox {
540 .label-checkbox {
541 float: left;
541 float: left;
542 }
542 }
543
543
544 &.field {
544 &.field {
545 margin: @space 0 @padding;
545 margin: @space 0 @padding;
546 }
546 }
547
547
548 &:first-child.field {
548 &:first-child.field {
549 margin-top: 0;
549 margin-top: 0;
550
550
551 .label {
551 .label {
552 margin-top: 0;
552 margin-top: 0;
553 padding-top: 0;
553 padding-top: 0;
554 }
554 }
555
555
556 .radios {
556 .radios {
557 padding-top: 0;
557 padding-top: 0;
558 }
558 }
559 }
559 }
560
560
561 .radios {
561 .radios {
562 position: relative;
562 position: relative;
563 width: 505px;
563 width: 505px;
564 }
564 }
565 }
565 }
566
566
567 //--- MODULES ------------------//
567 //--- MODULES ------------------//
568
568
569
569
570 // Server Announcement
570 // Server Announcement
571 #server-announcement {
571 #server-announcement {
572 width: 95%;
572 width: 95%;
573 margin: @padding auto;
573 margin: @padding auto;
574 padding: @padding;
574 padding: @padding;
575 border-width: 2px;
575 border-width: 2px;
576 border-style: solid;
576 border-style: solid;
577 .border-radius(2px);
577 .border-radius(2px);
578 font-weight: @text-bold-weight;
578 font-weight: @text-bold-weight;
579 font-family: @text-bold;
579 font-family: @text-bold;
580
580
581 &.info { border-color: @alert4; background-color: @alert4-inner; }
581 &.info { border-color: @alert4; background-color: @alert4-inner; }
582 &.warning { border-color: @alert3; background-color: @alert3-inner; }
582 &.warning { border-color: @alert3; background-color: @alert3-inner; }
583 &.error { border-color: @alert2; background-color: @alert2-inner; }
583 &.error { border-color: @alert2; background-color: @alert2-inner; }
584 &.success { border-color: @alert1; background-color: @alert1-inner; }
584 &.success { border-color: @alert1; background-color: @alert1-inner; }
585 &.neutral { border-color: @grey3; background-color: @grey6; }
585 &.neutral { border-color: @grey3; background-color: @grey6; }
586 }
586 }
587
587
588 // Fixed Sidebar Column
588 // Fixed Sidebar Column
589 .sidebar-col-wrapper {
589 .sidebar-col-wrapper {
590 padding-left: @sidebar-all-width;
590 padding-left: @sidebar-all-width;
591
591
592 .sidebar {
592 .sidebar {
593 width: @sidebar-width;
593 width: @sidebar-width;
594 margin-left: -@sidebar-all-width;
594 margin-left: -@sidebar-all-width;
595 }
595 }
596 }
596 }
597
597
598 .sidebar-col-wrapper.scw-small {
598 .sidebar-col-wrapper.scw-small {
599 padding-left: @sidebar-small-all-width;
599 padding-left: @sidebar-small-all-width;
600
600
601 .sidebar {
601 .sidebar {
602 width: @sidebar-small-width;
602 width: @sidebar-small-width;
603 margin-left: -@sidebar-small-all-width;
603 margin-left: -@sidebar-small-all-width;
604 }
604 }
605 }
605 }
606
606
607
607
608 // FOOTER
608 // FOOTER
609 #footer {
609 #footer {
610 padding: 0;
610 padding: 0;
611 text-align: center;
611 text-align: center;
612 vertical-align: middle;
612 vertical-align: middle;
613 color: @grey2;
613 color: @grey2;
614 font-size: 11px;
614 font-size: 11px;
615
615
616 p {
616 p {
617 margin: 0;
617 margin: 0;
618 padding: 1em;
618 padding: 1em;
619 line-height: 1em;
619 line-height: 1em;
620 }
620 }
621
621
622 .server-instance { //server instance
622 .server-instance { //server instance
623 display: none;
623 display: none;
624 }
624 }
625
625
626 .title {
626 .title {
627 float: none;
627 float: none;
628 margin: 0 auto;
628 margin: 0 auto;
629 }
629 }
630 }
630 }
631
631
632 button.close {
632 button.close {
633 padding: 0;
633 padding: 0;
634 cursor: pointer;
634 cursor: pointer;
635 background: transparent;
635 background: transparent;
636 border: 0;
636 border: 0;
637 .box-shadow(none);
637 .box-shadow(none);
638 -webkit-appearance: none;
638 -webkit-appearance: none;
639 }
639 }
640
640
641 .close {
641 .close {
642 float: right;
642 float: right;
643 font-size: 21px;
643 font-size: 21px;
644 font-family: @text-bootstrap;
644 font-family: @text-bootstrap;
645 line-height: 1em;
645 line-height: 1em;
646 font-weight: bold;
646 font-weight: bold;
647 color: @grey2;
647 color: @grey2;
648
648
649 &:hover,
649 &:hover,
650 &:focus {
650 &:focus {
651 color: @grey1;
651 color: @grey1;
652 text-decoration: none;
652 text-decoration: none;
653 cursor: pointer;
653 cursor: pointer;
654 }
654 }
655 }
655 }
656
656
657 // GRID
657 // GRID
658 .sorting,
658 .sorting,
659 .sorting_desc,
659 .sorting_desc,
660 .sorting_asc {
660 .sorting_asc {
661 cursor: pointer;
661 cursor: pointer;
662 }
662 }
663 .sorting_desc:after {
663 .sorting_desc:after {
664 content: "\00A0\25B2";
664 content: "\00A0\25B2";
665 font-size: .75em;
665 font-size: .75em;
666 }
666 }
667 .sorting_asc:after {
667 .sorting_asc:after {
668 content: "\00A0\25BC";
668 content: "\00A0\25BC";
669 font-size: .68em;
669 font-size: .68em;
670 }
670 }
671
671
672
672
673 .user_auth_tokens {
673 .user_auth_tokens {
674
674
675 &.truncate {
675 &.truncate {
676 white-space: nowrap;
676 white-space: nowrap;
677 overflow: hidden;
677 overflow: hidden;
678 text-overflow: ellipsis;
678 text-overflow: ellipsis;
679 }
679 }
680
680
681 .fields .field .input {
681 .fields .field .input {
682 margin: 0;
682 margin: 0;
683 }
683 }
684
684
685 input#description {
685 input#description {
686 width: 100px;
686 width: 100px;
687 margin: 0;
687 margin: 0;
688 }
688 }
689
689
690 .drop-menu {
690 .drop-menu {
691 // TODO: johbo: Remove this, should work out of the box when
691 // TODO: johbo: Remove this, should work out of the box when
692 // having multiple inputs inline
692 // having multiple inputs inline
693 margin: 0 0 0 5px;
693 margin: 0 0 0 5px;
694 }
694 }
695 }
695 }
696 #user_list_table {
696 #user_list_table {
697 .closed {
697 .closed {
698 background-color: @grey6;
698 background-color: @grey6;
699 }
699 }
700 }
700 }
701
701
702
702
703 input, textarea {
703 input, textarea {
704 &.disabled {
704 &.disabled {
705 opacity: .5;
705 opacity: .5;
706 }
706 }
707
707
708 &:hover {
708 &:hover {
709 border-color: @grey3;
709 border-color: @grey3;
710 box-shadow: @button-shadow;
710 box-shadow: @button-shadow;
711 }
711 }
712
712
713 &:focus {
713 &:focus {
714 border-color: @rcblue;
714 border-color: @rcblue;
715 box-shadow: @button-shadow;
715 box-shadow: @button-shadow;
716 }
716 }
717 }
717 }
718
718
719 // remove extra padding in firefox
719 // remove extra padding in firefox
720 input::-moz-focus-inner { border:0; padding:0 }
720 input::-moz-focus-inner { border:0; padding:0 }
721
721
722 .adjacent input {
722 .adjacent input {
723 margin-bottom: @padding;
723 margin-bottom: @padding;
724 }
724 }
725
725
726 .permissions_boxes {
726 .permissions_boxes {
727 display: block;
727 display: block;
728 }
728 }
729
729
730 //FORMS
730 //FORMS
731
731
732 .medium-inline,
732 .medium-inline,
733 input#description.medium-inline {
733 input#description.medium-inline {
734 display: inline;
734 display: inline;
735 width: @medium-inline-input-width;
735 width: @medium-inline-input-width;
736 min-width: 100px;
736 min-width: 100px;
737 }
737 }
738
738
739 select {
739 select {
740 //reset
740 //reset
741 -webkit-appearance: none;
741 -webkit-appearance: none;
742 -moz-appearance: none;
742 -moz-appearance: none;
743
743
744 display: inline-block;
744 display: inline-block;
745 height: 28px;
745 height: 28px;
746 width: auto;
746 width: auto;
747 margin: 0 @padding @padding 0;
747 margin: 0 @padding @padding 0;
748 padding: 0 18px 0 8px;
748 padding: 0 18px 0 8px;
749 line-height:1em;
749 line-height:1em;
750 font-size: @basefontsize;
750 font-size: @basefontsize;
751 border: @border-thickness solid @grey5;
751 border: @border-thickness solid @grey5;
752 border-radius: @border-radius;
752 border-radius: @border-radius;
753 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
753 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
754 color: @grey4;
754 color: @grey4;
755 box-shadow: @button-shadow;
755 box-shadow: @button-shadow;
756
756
757 &:after {
757 &:after {
758 content: "\00A0\25BE";
758 content: "\00A0\25BE";
759 }
759 }
760
760
761 &:focus, &:hover {
761 &:focus, &:hover {
762 outline: none;
762 outline: none;
763 border-color: @grey4;
763 border-color: @grey4;
764 color: @rcdarkblue;
764 color: @rcdarkblue;
765 }
765 }
766 }
766 }
767
767
768 option {
768 option {
769 &:focus {
769 &:focus {
770 outline: none;
770 outline: none;
771 }
771 }
772 }
772 }
773
773
774 input,
774 input,
775 textarea {
775 textarea {
776 padding: @input-padding;
776 padding: @input-padding;
777 border: @input-border-thickness solid @border-highlight-color;
777 border: @input-border-thickness solid @border-highlight-color;
778 .border-radius (@border-radius);
778 .border-radius (@border-radius);
779 font-family: @text-light;
779 font-family: @text-light;
780 font-size: @basefontsize;
780 font-size: @basefontsize;
781
781
782 &.input-sm {
782 &.input-sm {
783 padding: 5px;
783 padding: 5px;
784 }
784 }
785
785
786 &#description {
786 &#description {
787 min-width: @input-description-minwidth;
787 min-width: @input-description-minwidth;
788 min-height: 1em;
788 min-height: 1em;
789 padding: 10px;
789 padding: 10px;
790 }
790 }
791 }
791 }
792
792
793 .field-sm {
793 .field-sm {
794 input,
794 input,
795 textarea {
795 textarea {
796 padding: 5px;
796 padding: 5px;
797 }
797 }
798 }
798 }
799
799
800 textarea {
800 textarea {
801 display: block;
801 display: block;
802 clear: both;
802 clear: both;
803 width: 100%;
803 width: 100%;
804 min-height: 100px;
804 min-height: 100px;
805 margin-bottom: @padding;
805 margin-bottom: @padding;
806 .box-sizing(border-box);
806 .box-sizing(border-box);
807 overflow: auto;
807 overflow: auto;
808 }
808 }
809
809
810 label {
810 label {
811 font-family: @text-light;
811 font-family: @text-light;
812 }
812 }
813
813
814 // GRAVATARS
814 // GRAVATARS
815 // centers gravatar on username to the right
815 // centers gravatar on username to the right
816
816
817 .gravatar {
817 .gravatar {
818 display: inline;
818 display: inline;
819 min-width: 16px;
819 min-width: 16px;
820 min-height: 16px;
820 min-height: 16px;
821 margin: -5px 0;
821 margin: -5px 0;
822 padding: 0;
822 padding: 0;
823 line-height: 1em;
823 line-height: 1em;
824 box-sizing: content-box;
824 box-sizing: content-box;
825 border-radius: 50%;
825 border-radius: 50%;
826
826
827 &.gravatar-large {
827 &.gravatar-large {
828 margin: -0.5em .25em -0.5em 0;
828 margin: -0.5em .25em -0.5em 0;
829 }
829 }
830
830
831 & + .user {
831 & + .user {
832 display: inline;
832 display: inline;
833 margin: 0;
833 margin: 0;
834 padding: 0 0 0 .17em;
834 padding: 0 0 0 .17em;
835 line-height: 1em;
835 line-height: 1em;
836 }
836 }
837
837
838 & + .no-margin {
838 & + .no-margin {
839 margin: 0
839 margin: 0
840 }
840 }
841
841
842 }
842 }
843
843
844 .user-inline-data {
844 .user-inline-data {
845 display: inline-block;
845 display: inline-block;
846 float: left;
846 float: left;
847 padding-left: .5em;
847 padding-left: .5em;
848 line-height: 1.3em;
848 line-height: 1.3em;
849 }
849 }
850
850
851 .rc-user { // gravatar + user wrapper
851 .rc-user { // gravatar + user wrapper
852 float: left;
852 float: left;
853 position: relative;
853 position: relative;
854 min-width: 100px;
854 min-width: 100px;
855 max-width: 200px;
855 max-width: 200px;
856 min-height: (@gravatar-size + @border-thickness * 2); // account for border
856 min-height: (@gravatar-size + @border-thickness * 2); // account for border
857 display: block;
857 display: block;
858 padding: 0 0 0 (@gravatar-size + @basefontsize/4);
858 padding: 0 0 0 (@gravatar-size + @basefontsize/4);
859
859
860
860
861 .gravatar {
861 .gravatar {
862 display: block;
862 display: block;
863 position: absolute;
863 position: absolute;
864 top: 0;
864 top: 0;
865 left: 0;
865 left: 0;
866 min-width: @gravatar-size;
866 min-width: @gravatar-size;
867 min-height: @gravatar-size;
867 min-height: @gravatar-size;
868 margin: 0;
868 margin: 0;
869 }
869 }
870
870
871 .user {
871 .user {
872 display: block;
872 display: block;
873 max-width: 175px;
873 max-width: 175px;
874 padding-top: 2px;
874 padding-top: 2px;
875 overflow: hidden;
875 overflow: hidden;
876 text-overflow: ellipsis;
876 text-overflow: ellipsis;
877 }
877 }
878 }
878 }
879
879
880 .gist-gravatar,
880 .gist-gravatar,
881 .journal_container {
881 .journal_container {
882 .gravatar-large {
882 .gravatar-large {
883 margin: 0 .5em -10px 0;
883 margin: 0 .5em -10px 0;
884 }
884 }
885 }
885 }
886
886
887 .gist-type-fields {
887 .gist-type-fields {
888 line-height: 30px;
888 line-height: 30px;
889 height: 30px;
889 height: 30px;
890
890
891 .gist-type-fields-wrapper {
891 .gist-type-fields-wrapper {
892 vertical-align: middle;
892 vertical-align: middle;
893 display: inline-block;
893 display: inline-block;
894 line-height: 25px;
894 line-height: 25px;
895 }
895 }
896 }
896 }
897
897
898 // ADMIN SETTINGS
898 // ADMIN SETTINGS
899
899
900 // Tag Patterns
900 // Tag Patterns
901 .tag_patterns {
901 .tag_patterns {
902 .tag_input {
902 .tag_input {
903 margin-bottom: @padding;
903 margin-bottom: @padding;
904 }
904 }
905 }
905 }
906
906
907 .locked_input {
907 .locked_input {
908 position: relative;
908 position: relative;
909
909
910 input {
910 input {
911 display: inline;
911 display: inline;
912 margin: 3px 5px 0px 0px;
912 margin: 3px 5px 0px 0px;
913 }
913 }
914
914
915 br {
915 br {
916 display: none;
916 display: none;
917 }
917 }
918
918
919 .error-message {
919 .error-message {
920 float: left;
920 float: left;
921 width: 100%;
921 width: 100%;
922 }
922 }
923
923
924 .lock_input_button {
924 .lock_input_button {
925 display: inline;
925 display: inline;
926 }
926 }
927
927
928 .help-block {
928 .help-block {
929 clear: both;
929 clear: both;
930 }
930 }
931 }
931 }
932
932
933 // Notifications
933 // Notifications
934
934
935 .notifications_buttons {
935 .notifications_buttons {
936 margin: 0 0 @space 0;
936 margin: 0 0 @space 0;
937 padding: 0;
937 padding: 0;
938
938
939 .btn {
939 .btn {
940 display: inline-block;
940 display: inline-block;
941 }
941 }
942 }
942 }
943
943
944 .notification-list {
944 .notification-list {
945
945
946 div {
946 div {
947 vertical-align: middle;
947 vertical-align: middle;
948 }
948 }
949
949
950 .container {
950 .container {
951 display: block;
951 display: block;
952 margin: 0 0 @padding 0;
952 margin: 0 0 @padding 0;
953 }
953 }
954
954
955 .delete-notifications {
955 .delete-notifications {
956 margin-left: @padding;
956 margin-left: @padding;
957 text-align: right;
957 text-align: right;
958 cursor: pointer;
958 cursor: pointer;
959 }
959 }
960
960
961 .read-notifications {
961 .read-notifications {
962 margin-left: @padding/2;
962 margin-left: @padding/2;
963 text-align: right;
963 text-align: right;
964 width: 35px;
964 width: 35px;
965 cursor: pointer;
965 cursor: pointer;
966 }
966 }
967
967
968 .icon-minus-sign {
968 .icon-minus-sign {
969 color: @alert2;
969 color: @alert2;
970 }
970 }
971
971
972 .icon-ok-sign {
972 .icon-ok-sign {
973 color: @alert1;
973 color: @alert1;
974 }
974 }
975 }
975 }
976
976
977 .user_settings {
977 .user_settings {
978 float: left;
978 float: left;
979 clear: both;
979 clear: both;
980 display: block;
980 display: block;
981 width: 100%;
981 width: 100%;
982
982
983 .gravatar_box {
983 .gravatar_box {
984 margin-bottom: @padding;
984 margin-bottom: @padding;
985
985
986 &:after {
986 &:after {
987 content: " ";
987 content: " ";
988 clear: both;
988 clear: both;
989 width: 100%;
989 width: 100%;
990 }
990 }
991 }
991 }
992
992
993 .fields .field {
993 .fields .field {
994 clear: both;
994 clear: both;
995 }
995 }
996 }
996 }
997
997
998 .advanced_settings {
998 .advanced_settings {
999 margin-bottom: @space;
999 margin-bottom: @space;
1000
1000
1001 .help-block {
1001 .help-block {
1002 margin-left: 0;
1002 margin-left: 0;
1003 }
1003 }
1004
1004
1005 button + .help-block {
1005 button + .help-block {
1006 margin-top: @padding;
1006 margin-top: @padding;
1007 }
1007 }
1008 }
1008 }
1009
1009
1010 // admin settings radio buttons and labels
1010 // admin settings radio buttons and labels
1011 .label-2 {
1011 .label-2 {
1012 float: left;
1012 float: left;
1013 width: @label2-width;
1013 width: @label2-width;
1014
1014
1015 label {
1015 label {
1016 color: @grey1;
1016 color: @grey1;
1017 }
1017 }
1018 }
1018 }
1019 .checkboxes {
1019 .checkboxes {
1020 float: left;
1020 float: left;
1021 width: @checkboxes-width;
1021 width: @checkboxes-width;
1022 margin-bottom: @padding;
1022 margin-bottom: @padding;
1023
1023
1024 .checkbox {
1024 .checkbox {
1025 width: 100%;
1025 width: 100%;
1026
1026
1027 label {
1027 label {
1028 margin: 0;
1028 margin: 0;
1029 padding: 0;
1029 padding: 0;
1030 }
1030 }
1031 }
1031 }
1032
1032
1033 .checkbox + .checkbox {
1033 .checkbox + .checkbox {
1034 display: inline-block;
1034 display: inline-block;
1035 }
1035 }
1036
1036
1037 label {
1037 label {
1038 margin-right: 1em;
1038 margin-right: 1em;
1039 }
1039 }
1040 }
1040 }
1041
1041
1042 // CHANGELOG
1042 // CHANGELOG
1043 .container_header {
1043 .container_header {
1044 float: left;
1044 float: left;
1045 display: block;
1045 display: block;
1046 width: 100%;
1046 width: 100%;
1047 margin: @padding 0 @padding;
1047 margin: @padding 0 @padding;
1048
1048
1049 #filter_changelog {
1049 #filter_changelog {
1050 float: left;
1050 float: left;
1051 margin-right: @padding;
1051 margin-right: @padding;
1052 }
1052 }
1053
1053
1054 .breadcrumbs_light {
1054 .breadcrumbs_light {
1055 display: inline-block;
1055 display: inline-block;
1056 }
1056 }
1057 }
1057 }
1058
1058
1059 .info_box {
1059 .info_box {
1060 float: right;
1060 float: right;
1061 }
1061 }
1062
1062
1063
1063
1064
1064
1065 #graph_content{
1065 #graph_content{
1066
1066
1067 // adjust for table headers so that graph renders properly
1067 // adjust for table headers so that graph renders properly
1068 // #graph_nodes padding - table cell padding
1068 // #graph_nodes padding - table cell padding
1069 padding-top: (@space - (@basefontsize * 2.4));
1069 padding-top: (@space - (@basefontsize * 2.4));
1070
1070
1071 &.graph_full_width {
1071 &.graph_full_width {
1072 width: 100%;
1072 width: 100%;
1073 max-width: 100%;
1073 max-width: 100%;
1074 }
1074 }
1075 }
1075 }
1076
1076
1077 #graph {
1077 #graph {
1078
1078
1079 .pagination-left {
1079 .pagination-left {
1080 float: left;
1080 float: left;
1081 clear: both;
1081 clear: both;
1082 }
1082 }
1083
1083
1084 .log-container {
1084 .log-container {
1085 max-width: 345px;
1085 max-width: 345px;
1086
1086
1087 .message{
1087 .message{
1088 max-width: 340px;
1088 max-width: 340px;
1089 }
1089 }
1090 }
1090 }
1091
1091
1092 .graph-col-wrapper {
1092 .graph-col-wrapper {
1093
1093
1094 #graph_nodes {
1094 #graph_nodes {
1095 width: 100px;
1095 width: 100px;
1096 position: absolute;
1096 position: absolute;
1097 left: 70px;
1097 left: 70px;
1098 z-index: -1;
1098 z-index: -1;
1099 }
1099 }
1100 }
1100 }
1101
1101
1102 .load-more-commits {
1102 .load-more-commits {
1103 text-align: center;
1103 text-align: center;
1104 }
1104 }
1105 .load-more-commits:hover {
1105 .load-more-commits:hover {
1106 background-color: @grey7;
1106 background-color: @grey7;
1107 }
1107 }
1108 .load-more-commits {
1108 .load-more-commits {
1109 a {
1109 a {
1110 display: block;
1110 display: block;
1111 }
1111 }
1112 }
1112 }
1113 }
1113 }
1114
1114
1115 .obsolete-toggle {
1115 .obsolete-toggle {
1116 line-height: 30px;
1116 line-height: 30px;
1117 margin-left: -15px;
1117 margin-left: -15px;
1118 }
1118 }
1119
1119
1120 #rev_range_container, #rev_range_clear, #rev_range_more {
1120 #rev_range_container, #rev_range_clear, #rev_range_more {
1121 margin-top: -5px;
1121 margin-top: -5px;
1122 margin-bottom: -5px;
1122 margin-bottom: -5px;
1123 }
1123 }
1124
1124
1125 #filter_changelog {
1125 #filter_changelog {
1126 float: left;
1126 float: left;
1127 }
1127 }
1128
1128
1129
1129
1130 //--- THEME ------------------//
1130 //--- THEME ------------------//
1131
1131
1132 #logo {
1132 #logo {
1133 float: left;
1133 float: left;
1134 margin: 9px 0 0 0;
1134 margin: 9px 0 0 0;
1135
1135
1136 .header {
1136 .header {
1137 background-color: transparent;
1137 background-color: transparent;
1138 }
1138 }
1139
1139
1140 a {
1140 a {
1141 display: inline-block;
1141 display: inline-block;
1142 }
1142 }
1143
1143
1144 img {
1144 img {
1145 height:30px;
1145 height:30px;
1146 }
1146 }
1147 }
1147 }
1148
1148
1149 .logo-wrapper {
1149 .logo-wrapper {
1150 float:left;
1150 float:left;
1151 }
1151 }
1152
1152
1153 .branding {
1153 .branding {
1154 float: left;
1154 float: left;
1155 padding: 9px 2px;
1155 padding: 9px 2px;
1156 line-height: 1em;
1156 line-height: 1em;
1157 font-size: @navigation-fontsize;
1157 font-size: @navigation-fontsize;
1158
1158
1159 a {
1159 a {
1160 color: @grey5
1160 color: @grey5
1161 }
1161 }
1162 @media screen and (max-width: 1200px) {
1162 @media screen and (max-width: 1200px) {
1163 display: none;
1163 display: none;
1164 }
1164 }
1165 }
1165 }
1166
1166
1167 img {
1167 img {
1168 border: none;
1168 border: none;
1169 outline: none;
1169 outline: none;
1170 }
1170 }
1171 user-profile-header
1171 user-profile-header
1172 label {
1172 label {
1173
1173
1174 input[type="checkbox"] {
1174 input[type="checkbox"] {
1175 margin-right: 1em;
1175 margin-right: 1em;
1176 }
1176 }
1177 input[type="radio"] {
1177 input[type="radio"] {
1178 margin-right: 1em;
1178 margin-right: 1em;
1179 }
1179 }
1180 }
1180 }
1181
1181
1182 .review-status {
1182 .review-status {
1183 &.under_review {
1183 &.under_review {
1184 color: @alert3;
1184 color: @alert3;
1185 }
1185 }
1186 &.approved {
1186 &.approved {
1187 color: @alert1;
1187 color: @alert1;
1188 }
1188 }
1189 &.rejected,
1189 &.rejected,
1190 &.forced_closed{
1190 &.forced_closed{
1191 color: @alert2;
1191 color: @alert2;
1192 }
1192 }
1193 &.not_reviewed {
1193 &.not_reviewed {
1194 color: @grey5;
1194 color: @grey5;
1195 }
1195 }
1196 }
1196 }
1197
1197
1198 .review-status-under_review {
1198 .review-status-under_review {
1199 color: @alert3;
1199 color: @alert3;
1200 }
1200 }
1201 .status-tag-under_review {
1201 .status-tag-under_review {
1202 border-color: @alert3;
1202 border-color: @alert3;
1203 }
1203 }
1204
1204
1205 .review-status-approved {
1205 .review-status-approved {
1206 color: @alert1;
1206 color: @alert1;
1207 }
1207 }
1208 .status-tag-approved {
1208 .status-tag-approved {
1209 border-color: @alert1;
1209 border-color: @alert1;
1210 }
1210 }
1211
1211
1212 .review-status-rejected,
1212 .review-status-rejected,
1213 .review-status-forced_closed {
1213 .review-status-forced_closed {
1214 color: @alert2;
1214 color: @alert2;
1215 }
1215 }
1216 .status-tag-rejected,
1216 .status-tag-rejected,
1217 .status-tag-forced_closed {
1217 .status-tag-forced_closed {
1218 border-color: @alert2;
1218 border-color: @alert2;
1219 }
1219 }
1220
1220
1221 .review-status-not_reviewed {
1221 .review-status-not_reviewed {
1222 color: @grey5;
1222 color: @grey5;
1223 }
1223 }
1224 .status-tag-not_reviewed {
1224 .status-tag-not_reviewed {
1225 border-color: @grey5;
1225 border-color: @grey5;
1226 }
1226 }
1227
1227
1228 .test_pattern_preview {
1228 .test_pattern_preview {
1229 margin: @space 0;
1229 margin: @space 0;
1230
1230
1231 p {
1231 p {
1232 margin-bottom: 0;
1232 margin-bottom: 0;
1233 border-bottom: @border-thickness solid @border-default-color;
1233 border-bottom: @border-thickness solid @border-default-color;
1234 color: @grey3;
1234 color: @grey3;
1235 }
1235 }
1236
1236
1237 .btn {
1237 .btn {
1238 margin-bottom: @padding;
1238 margin-bottom: @padding;
1239 }
1239 }
1240 }
1240 }
1241 #test_pattern_result {
1241 #test_pattern_result {
1242 display: none;
1242 display: none;
1243 &:extend(pre);
1243 &:extend(pre);
1244 padding: .9em;
1244 padding: .9em;
1245 color: @grey3;
1245 color: @grey3;
1246 background-color: @grey7;
1246 background-color: @grey7;
1247 border-right: @border-thickness solid @border-default-color;
1247 border-right: @border-thickness solid @border-default-color;
1248 border-bottom: @border-thickness solid @border-default-color;
1248 border-bottom: @border-thickness solid @border-default-color;
1249 border-left: @border-thickness solid @border-default-color;
1249 border-left: @border-thickness solid @border-default-color;
1250 }
1250 }
1251
1251
1252 #repo_vcs_settings {
1252 #repo_vcs_settings {
1253 #inherit_overlay_vcs_default {
1253 #inherit_overlay_vcs_default {
1254 display: none;
1254 display: none;
1255 }
1255 }
1256 #inherit_overlay_vcs_custom {
1256 #inherit_overlay_vcs_custom {
1257 display: custom;
1257 display: custom;
1258 }
1258 }
1259 &.inherited {
1259 &.inherited {
1260 #inherit_overlay_vcs_default {
1260 #inherit_overlay_vcs_default {
1261 display: block;
1261 display: block;
1262 }
1262 }
1263 #inherit_overlay_vcs_custom {
1263 #inherit_overlay_vcs_custom {
1264 display: none;
1264 display: none;
1265 }
1265 }
1266 }
1266 }
1267 }
1267 }
1268
1268
1269 .issue-tracker-link {
1269 .issue-tracker-link {
1270 color: @rcblue;
1270 color: @rcblue;
1271 }
1271 }
1272
1272
1273 // Issue Tracker Table Show/Hide
1273 // Issue Tracker Table Show/Hide
1274 #repo_issue_tracker {
1274 #repo_issue_tracker {
1275 #inherit_overlay {
1275 #inherit_overlay {
1276 display: none;
1276 display: none;
1277 }
1277 }
1278 #custom_overlay {
1278 #custom_overlay {
1279 display: custom;
1279 display: custom;
1280 }
1280 }
1281 &.inherited {
1281 &.inherited {
1282 #inherit_overlay {
1282 #inherit_overlay {
1283 display: block;
1283 display: block;
1284 }
1284 }
1285 #custom_overlay {
1285 #custom_overlay {
1286 display: none;
1286 display: none;
1287 }
1287 }
1288 }
1288 }
1289 }
1289 }
1290 table.issuetracker {
1290 table.issuetracker {
1291 &.readonly {
1291 &.readonly {
1292 tr, td {
1292 tr, td {
1293 color: @grey3;
1293 color: @grey3;
1294 }
1294 }
1295 }
1295 }
1296 .edit {
1296 .edit {
1297 display: none;
1297 display: none;
1298 }
1298 }
1299 .editopen {
1299 .editopen {
1300 .edit {
1300 .edit {
1301 display: inline;
1301 display: inline;
1302 }
1302 }
1303 .entry {
1303 .entry {
1304 display: none;
1304 display: none;
1305 }
1305 }
1306 }
1306 }
1307 tr td.td-action {
1307 tr td.td-action {
1308 min-width: 117px;
1308 min-width: 117px;
1309 }
1309 }
1310 td input {
1310 td input {
1311 max-width: none;
1311 max-width: none;
1312 min-width: 30px;
1312 min-width: 30px;
1313 width: 80%;
1313 width: 80%;
1314 }
1314 }
1315 .issuetracker_pref input {
1315 .issuetracker_pref input {
1316 width: 40%;
1316 width: 40%;
1317 }
1317 }
1318 input.edit_issuetracker_update {
1318 input.edit_issuetracker_update {
1319 margin-right: 0;
1319 margin-right: 0;
1320 width: auto;
1320 width: auto;
1321 }
1321 }
1322 }
1322 }
1323
1323
1324 table.integrations {
1324 table.integrations {
1325 .td-icon {
1325 .td-icon {
1326 width: 20px;
1326 width: 20px;
1327 .integration-icon {
1327 .integration-icon {
1328 height: 20px;
1328 height: 20px;
1329 width: 20px;
1329 width: 20px;
1330 }
1330 }
1331 }
1331 }
1332 }
1332 }
1333
1333
1334 .integrations {
1334 .integrations {
1335 a.integration-box {
1335 a.integration-box {
1336 color: @text-color;
1336 color: @text-color;
1337 &:hover {
1337 &:hover {
1338 .panel {
1338 .panel {
1339 background: #fbfbfb;
1339 background: #fbfbfb;
1340 }
1340 }
1341 }
1341 }
1342 .integration-icon {
1342 .integration-icon {
1343 width: 30px;
1343 width: 30px;
1344 height: 30px;
1344 height: 30px;
1345 margin-right: 20px;
1345 margin-right: 20px;
1346 float: left;
1346 float: left;
1347 }
1347 }
1348
1348
1349 .panel-body {
1349 .panel-body {
1350 padding: 10px;
1350 padding: 10px;
1351 }
1351 }
1352 .panel {
1352 .panel {
1353 margin-bottom: 10px;
1353 margin-bottom: 10px;
1354 }
1354 }
1355 h2 {
1355 h2 {
1356 display: inline-block;
1356 display: inline-block;
1357 margin: 0;
1357 margin: 0;
1358 min-width: 140px;
1358 min-width: 140px;
1359 }
1359 }
1360 }
1360 }
1361 a.integration-box.dummy-integration {
1361 a.integration-box.dummy-integration {
1362 color: @grey4
1362 color: @grey4
1363 }
1363 }
1364 }
1364 }
1365
1365
1366 //Permissions Settings
1366 //Permissions Settings
1367 #add_perm {
1367 #add_perm {
1368 margin: 0 0 @padding;
1368 margin: 0 0 @padding;
1369 cursor: pointer;
1369 cursor: pointer;
1370 }
1370 }
1371
1371
1372 .perm_ac {
1372 .perm_ac {
1373 input {
1373 input {
1374 width: 95%;
1374 width: 95%;
1375 }
1375 }
1376 }
1376 }
1377
1377
1378 .autocomplete-suggestions {
1378 .autocomplete-suggestions {
1379 width: auto !important; // overrides autocomplete.js
1379 width: auto !important; // overrides autocomplete.js
1380 min-width: 278px;
1380 min-width: 278px;
1381 margin: 0;
1381 margin: 0;
1382 border: @border-thickness solid @grey5;
1382 border: @border-thickness solid @grey5;
1383 border-radius: @border-radius;
1383 border-radius: @border-radius;
1384 color: @grey2;
1384 color: @grey2;
1385 background-color: white;
1385 background-color: white;
1386 }
1386 }
1387
1387
1388 .autocomplete-qfilter-suggestions {
1388 .autocomplete-qfilter-suggestions {
1389 width: auto !important; // overrides autocomplete.js
1389 width: auto !important; // overrides autocomplete.js
1390 max-height: 100% !important;
1390 max-height: 100% !important;
1391 min-width: 376px;
1391 min-width: 376px;
1392 margin: 0;
1392 margin: 0;
1393 border: @border-thickness solid @grey5;
1393 border: @border-thickness solid @grey5;
1394 color: @grey2;
1394 color: @grey2;
1395 background-color: white;
1395 background-color: white;
1396 }
1396 }
1397
1397
1398 .autocomplete-selected {
1398 .autocomplete-selected {
1399 background: #F0F0F0;
1399 background: #F0F0F0;
1400 }
1400 }
1401
1401
1402 .ac-container-wrap {
1402 .ac-container-wrap {
1403 margin: 0;
1403 margin: 0;
1404 padding: 8px;
1404 padding: 8px;
1405 border-bottom: @border-thickness solid @grey5;
1405 border-bottom: @border-thickness solid @grey5;
1406 list-style-type: none;
1406 list-style-type: none;
1407 cursor: pointer;
1407 cursor: pointer;
1408
1408
1409 &:hover {
1409 &:hover {
1410 background-color: @grey7;
1410 background-color: @grey7;
1411 }
1411 }
1412
1412
1413 img {
1413 img {
1414 height: @gravatar-size;
1414 height: @gravatar-size;
1415 width: @gravatar-size;
1415 width: @gravatar-size;
1416 margin-right: 1em;
1416 margin-right: 1em;
1417 }
1417 }
1418
1418
1419 strong {
1419 strong {
1420 font-weight: normal;
1420 font-weight: normal;
1421 }
1421 }
1422 }
1422 }
1423
1423
1424 // Settings Dropdown
1424 // Settings Dropdown
1425 .user-menu .container {
1425 .user-menu .container {
1426 padding: 0 4px;
1426 padding: 0 4px;
1427 margin: 0;
1427 margin: 0;
1428 }
1428 }
1429
1429
1430 .user-menu .gravatar {
1430 .user-menu .gravatar {
1431 cursor: pointer;
1431 cursor: pointer;
1432 }
1432 }
1433
1433
1434 .codeblock {
1434 .codeblock {
1435 margin-bottom: @padding;
1435 margin-bottom: @padding;
1436 clear: both;
1436 clear: both;
1437
1437
1438 .stats {
1438 .stats {
1439 overflow: hidden;
1439 overflow: hidden;
1440 }
1440 }
1441
1441
1442 .message{
1442 .message{
1443 textarea{
1443 textarea{
1444 margin: 0;
1444 margin: 0;
1445 }
1445 }
1446 }
1446 }
1447
1447
1448 .code-header {
1448 .code-header {
1449 .stats {
1449 .stats {
1450 line-height: 2em;
1450 line-height: 2em;
1451
1451
1452 .revision_id {
1452 .revision_id {
1453 margin-left: 0;
1453 margin-left: 0;
1454 }
1454 }
1455 .buttons {
1455 .buttons {
1456 padding-right: 0;
1456 padding-right: 0;
1457 }
1457 }
1458 }
1458 }
1459
1459
1460 .item{
1460 .item{
1461 margin-right: 0.5em;
1461 margin-right: 0.5em;
1462 }
1462 }
1463 }
1463 }
1464
1464
1465 #editor_container {
1465 #editor_container {
1466 position: relative;
1466 position: relative;
1467 margin: @padding 10px;
1467 margin: @padding 10px;
1468 }
1468 }
1469 }
1469 }
1470
1470
1471 #file_history_container {
1471 #file_history_container {
1472 display: none;
1472 display: none;
1473 }
1473 }
1474
1474
1475 .file-history-inner {
1475 .file-history-inner {
1476 margin-bottom: 10px;
1476 margin-bottom: 10px;
1477 }
1477 }
1478
1478
1479 // Pull Requests
1479 // Pull Requests
1480 .summary-details {
1480 .summary-details {
1481 width: 72%;
1481 width: 72%;
1482 }
1482 }
1483 .pr-summary {
1483 .pr-summary {
1484 border-bottom: @border-thickness solid @grey5;
1484 border-bottom: @border-thickness solid @grey5;
1485 margin-bottom: @space;
1485 margin-bottom: @space;
1486 }
1486 }
1487
1487
1488 .reviewers-title {
1488 .reviewers-title {
1489 width: 25%;
1489 width: 25%;
1490 min-width: 200px;
1490 min-width: 200px;
1491
1491
1492 &.first-panel {
1492 &.first-panel {
1493 margin-top: 34px;
1493 margin-top: 34px;
1494 }
1494 }
1495 }
1495 }
1496
1496
1497 .reviewers {
1497 .reviewers {
1498 width: 25%;
1498 width: 25%;
1499 min-width: 200px;
1499 min-width: 200px;
1500 }
1500 }
1501 .reviewers ul li {
1501 .reviewers ul li {
1502 position: relative;
1502 position: relative;
1503 width: 100%;
1503 width: 100%;
1504 padding-bottom: 8px;
1504 padding-bottom: 8px;
1505 list-style-type: none;
1505 list-style-type: none;
1506 }
1506 }
1507
1507
1508 .reviewer_entry {
1508 .reviewer_entry {
1509 min-height: 55px;
1509 min-height: 55px;
1510 }
1510 }
1511
1511
1512 .reviewers_member {
1512 .reviewers_member {
1513 width: 100%;
1513 width: 100%;
1514 overflow: auto;
1514 overflow: auto;
1515 }
1515 }
1516 .reviewer_reason {
1516 .reviewer_reason {
1517 padding-left: 20px;
1517 padding-left: 20px;
1518 line-height: 1.5em;
1518 line-height: 1.5em;
1519 }
1519 }
1520 .reviewer_status {
1520 .reviewer_status {
1521 display: inline-block;
1521 display: inline-block;
1522 width: 25px;
1522 width: 25px;
1523 min-width: 25px;
1523 min-width: 25px;
1524 height: 1.2em;
1524 height: 1.2em;
1525 line-height: 1em;
1525 line-height: 1em;
1526 }
1526 }
1527
1527
1528 .reviewer_name {
1528 .reviewer_name {
1529 display: inline-block;
1529 display: inline-block;
1530 max-width: 83%;
1530 max-width: 83%;
1531 padding-right: 20px;
1531 padding-right: 20px;
1532 vertical-align: middle;
1532 vertical-align: middle;
1533 line-height: 1;
1533 line-height: 1;
1534
1534
1535 .rc-user {
1535 .rc-user {
1536 min-width: 0;
1536 min-width: 0;
1537 margin: -2px 1em 0 0;
1537 margin: -2px 1em 0 0;
1538 }
1538 }
1539
1539
1540 .reviewer {
1540 .reviewer {
1541 float: left;
1541 float: left;
1542 }
1542 }
1543 }
1543 }
1544
1544
1545 .reviewer_member_mandatory {
1545 .reviewer_member_mandatory {
1546 position: absolute;
1546 position: absolute;
1547 left: 15px;
1547 left: 15px;
1548 top: 8px;
1548 top: 8px;
1549 width: 16px;
1549 width: 16px;
1550 font-size: 11px;
1550 font-size: 11px;
1551 margin: 0;
1551 margin: 0;
1552 padding: 0;
1552 padding: 0;
1553 color: black;
1553 color: black;
1554 }
1554 }
1555
1555
1556 .reviewer_member_mandatory_remove,
1556 .reviewer_member_mandatory_remove,
1557 .reviewer_member_remove {
1557 .reviewer_member_remove {
1558 position: absolute;
1558 position: absolute;
1559 right: 0;
1559 right: 0;
1560 top: 0;
1560 top: 0;
1561 width: 16px;
1561 width: 16px;
1562 margin-bottom: 10px;
1562 margin-bottom: 10px;
1563 padding: 0;
1563 padding: 0;
1564 color: black;
1564 color: black;
1565 }
1565 }
1566
1566
1567 .reviewer_member_mandatory_remove {
1567 .reviewer_member_mandatory_remove {
1568 color: @grey4;
1568 color: @grey4;
1569 }
1569 }
1570
1570
1571 .reviewer_member_status {
1571 .reviewer_member_status {
1572 margin-top: 5px;
1572 margin-top: 5px;
1573 }
1573 }
1574 .pr-summary #summary{
1574 .pr-summary #summary{
1575 width: 100%;
1575 width: 100%;
1576 }
1576 }
1577 .pr-summary .action_button:hover {
1577 .pr-summary .action_button:hover {
1578 border: 0;
1578 border: 0;
1579 cursor: pointer;
1579 cursor: pointer;
1580 }
1580 }
1581 .pr-details-title {
1581 .pr-details-title {
1582 padding-bottom: 8px;
1582 padding-bottom: 8px;
1583 border-bottom: @border-thickness solid @grey5;
1583 border-bottom: @border-thickness solid @grey5;
1584
1584
1585 .action_button.disabled {
1585 .action_button.disabled {
1586 color: @grey4;
1586 color: @grey4;
1587 cursor: inherit;
1587 cursor: inherit;
1588 }
1588 }
1589 .action_button {
1589 .action_button {
1590 color: @rcblue;
1590 color: @rcblue;
1591 }
1591 }
1592 }
1592 }
1593 .pr-details-content {
1593 .pr-details-content {
1594 margin-top: @textmargin - 5;
1594 margin-top: @textmargin - 5;
1595 margin-bottom: @textmargin - 5;
1595 margin-bottom: @textmargin - 5;
1596 }
1596 }
1597
1597
1598 .pr-reviewer-rules {
1598 .pr-reviewer-rules {
1599 padding: 10px 0px 20px 0px;
1599 padding: 10px 0px 20px 0px;
1600 }
1600 }
1601
1601
1602 .todo-resolved {
1602 .todo-resolved {
1603 text-decoration: line-through;
1603 text-decoration: line-through;
1604 }
1604 }
1605
1605
1606 .todo-table {
1606 .todo-table {
1607 width: 100%;
1607 width: 100%;
1608
1608
1609 td {
1609 td {
1610 padding: 5px 0px;
1610 padding: 5px 0px;
1611 }
1611 }
1612
1612
1613 .td-todo-number {
1613 .td-todo-number {
1614 text-align: left;
1614 text-align: left;
1615 white-space: nowrap;
1615 white-space: nowrap;
1616 width: 15%;
1616 width: 15%;
1617 }
1617 }
1618
1618
1619 .td-todo-gravatar {
1619 .td-todo-gravatar {
1620 width: 5%;
1620 width: 5%;
1621
1621
1622 img {
1622 img {
1623 margin: -3px 0;
1623 margin: -3px 0;
1624 }
1624 }
1625 }
1625 }
1626
1626
1627 }
1627 }
1628
1628
1629 .todo-comment-text-wrapper {
1629 .todo-comment-text-wrapper {
1630 display: inline-grid;
1630 display: inline-grid;
1631 }
1631 }
1632
1632
1633 .todo-comment-text {
1633 .todo-comment-text {
1634 margin-left: 5px;
1634 margin-left: 5px;
1635 white-space: nowrap;
1635 white-space: nowrap;
1636 overflow: hidden;
1636 overflow: hidden;
1637 text-overflow: ellipsis;
1637 text-overflow: ellipsis;
1638 }
1638 }
1639
1639
1640 .group_members {
1640 .group_members {
1641 margin-top: 0;
1641 margin-top: 0;
1642 padding: 0;
1642 padding: 0;
1643 list-style: outside none none;
1643 list-style: outside none none;
1644
1644
1645 img {
1645 img {
1646 height: @gravatar-size;
1646 height: @gravatar-size;
1647 width: @gravatar-size;
1647 width: @gravatar-size;
1648 margin-right: .5em;
1648 margin-right: .5em;
1649 margin-left: 3px;
1649 margin-left: 3px;
1650 }
1650 }
1651
1651
1652 .to-delete {
1652 .to-delete {
1653 .user {
1653 .user {
1654 text-decoration: line-through;
1654 text-decoration: line-through;
1655 }
1655 }
1656 }
1656 }
1657 }
1657 }
1658
1658
1659 .compare_view_commits_title {
1659 .compare_view_commits_title {
1660 .disabled {
1660 .disabled {
1661 cursor: inherit;
1661 cursor: inherit;
1662 &:hover{
1662 &:hover{
1663 background-color: inherit;
1663 background-color: inherit;
1664 color: inherit;
1664 color: inherit;
1665 }
1665 }
1666 }
1666 }
1667 }
1667 }
1668
1668
1669 .subtitle-compare {
1669 .subtitle-compare {
1670 margin: -15px 0px 0px 0px;
1670 margin: -15px 0px 0px 0px;
1671 }
1671 }
1672
1672
1673 // new entry in group_members
1673 // new entry in group_members
1674 .td-author-new-entry {
1674 .td-author-new-entry {
1675 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1675 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1676 }
1676 }
1677
1677
1678 .usergroup_member_remove {
1678 .usergroup_member_remove {
1679 width: 16px;
1679 width: 16px;
1680 margin-bottom: 10px;
1680 margin-bottom: 10px;
1681 padding: 0;
1681 padding: 0;
1682 color: black !important;
1682 color: black !important;
1683 cursor: pointer;
1683 cursor: pointer;
1684 }
1684 }
1685
1685
1686 .reviewer_ac .ac-input {
1686 .reviewer_ac .ac-input {
1687 width: 92%;
1687 width: 92%;
1688 margin-bottom: 1em;
1688 margin-bottom: 1em;
1689 }
1689 }
1690
1690
1691 .compare_view_commits tr{
1691 .compare_view_commits tr{
1692 height: 20px;
1692 height: 20px;
1693 }
1693 }
1694 .compare_view_commits td {
1694 .compare_view_commits td {
1695 vertical-align: top;
1695 vertical-align: top;
1696 padding-top: 10px;
1696 padding-top: 10px;
1697 }
1697 }
1698 .compare_view_commits .author {
1698 .compare_view_commits .author {
1699 margin-left: 5px;
1699 margin-left: 5px;
1700 }
1700 }
1701
1701
1702 .compare_view_commits {
1702 .compare_view_commits {
1703 .color-a {
1703 .color-a {
1704 color: @alert1;
1704 color: @alert1;
1705 }
1705 }
1706
1706
1707 .color-c {
1707 .color-c {
1708 color: @color3;
1708 color: @color3;
1709 }
1709 }
1710
1710
1711 .color-r {
1711 .color-r {
1712 color: @color5;
1712 color: @color5;
1713 }
1713 }
1714
1714
1715 .color-a-bg {
1715 .color-a-bg {
1716 background-color: @alert1;
1716 background-color: @alert1;
1717 }
1717 }
1718
1718
1719 .color-c-bg {
1719 .color-c-bg {
1720 background-color: @alert3;
1720 background-color: @alert3;
1721 }
1721 }
1722
1722
1723 .color-r-bg {
1723 .color-r-bg {
1724 background-color: @alert2;
1724 background-color: @alert2;
1725 }
1725 }
1726
1726
1727 .color-a-border {
1727 .color-a-border {
1728 border: 1px solid @alert1;
1728 border: 1px solid @alert1;
1729 }
1729 }
1730
1730
1731 .color-c-border {
1731 .color-c-border {
1732 border: 1px solid @alert3;
1732 border: 1px solid @alert3;
1733 }
1733 }
1734
1734
1735 .color-r-border {
1735 .color-r-border {
1736 border: 1px solid @alert2;
1736 border: 1px solid @alert2;
1737 }
1737 }
1738
1738
1739 .commit-change-indicator {
1739 .commit-change-indicator {
1740 width: 15px;
1740 width: 15px;
1741 height: 15px;
1741 height: 15px;
1742 position: relative;
1742 position: relative;
1743 left: 15px;
1743 left: 15px;
1744 }
1744 }
1745
1745
1746 .commit-change-content {
1746 .commit-change-content {
1747 text-align: center;
1747 text-align: center;
1748 vertical-align: middle;
1748 vertical-align: middle;
1749 line-height: 15px;
1749 line-height: 15px;
1750 }
1750 }
1751 }
1751 }
1752
1752
1753 .compare_view_filepath {
1753 .compare_view_filepath {
1754 color: @grey1;
1754 color: @grey1;
1755 }
1755 }
1756
1756
1757 .show_more {
1757 .show_more {
1758 display: inline-block;
1758 display: inline-block;
1759 width: 0;
1759 width: 0;
1760 height: 0;
1760 height: 0;
1761 vertical-align: middle;
1761 vertical-align: middle;
1762 content: "";
1762 content: "";
1763 border: 4px solid;
1763 border: 4px solid;
1764 border-right-color: transparent;
1764 border-right-color: transparent;
1765 border-bottom-color: transparent;
1765 border-bottom-color: transparent;
1766 border-left-color: transparent;
1766 border-left-color: transparent;
1767 font-size: 0;
1767 font-size: 0;
1768 }
1768 }
1769
1769
1770 .journal_more .show_more {
1770 .journal_more .show_more {
1771 display: inline;
1771 display: inline;
1772
1772
1773 &:after {
1773 &:after {
1774 content: none;
1774 content: none;
1775 }
1775 }
1776 }
1776 }
1777
1777
1778 .compare_view_commits .collapse_commit:after {
1778 .compare_view_commits .collapse_commit:after {
1779 cursor: pointer;
1779 cursor: pointer;
1780 content: "\00A0\25B4";
1780 content: "\00A0\25B4";
1781 margin-left: -3px;
1781 margin-left: -3px;
1782 font-size: 17px;
1782 font-size: 17px;
1783 color: @grey4;
1783 color: @grey4;
1784 }
1784 }
1785
1785
1786 .diff_links {
1786 .diff_links {
1787 margin-left: 8px;
1787 margin-left: 8px;
1788 }
1788 }
1789
1789
1790 #pull_request_overview {
1790 #pull_request_overview {
1791 div.ancestor {
1791 div.ancestor {
1792 margin: -33px 0;
1792 margin: -33px 0;
1793 }
1793 }
1794 }
1794 }
1795
1795
1796 div.ancestor {
1796 div.ancestor {
1797 line-height: 33px;
1797 line-height: 33px;
1798 }
1798 }
1799
1799
1800 .cs_icon_td input[type="checkbox"] {
1800 .cs_icon_td input[type="checkbox"] {
1801 display: none;
1801 display: none;
1802 }
1802 }
1803
1803
1804 .cs_icon_td .expand_file_icon:after {
1804 .cs_icon_td .expand_file_icon:after {
1805 cursor: pointer;
1805 cursor: pointer;
1806 content: "\00A0\25B6";
1806 content: "\00A0\25B6";
1807 font-size: 12px;
1807 font-size: 12px;
1808 color: @grey4;
1808 color: @grey4;
1809 }
1809 }
1810
1810
1811 .cs_icon_td .collapse_file_icon:after {
1811 .cs_icon_td .collapse_file_icon:after {
1812 cursor: pointer;
1812 cursor: pointer;
1813 content: "\00A0\25BC";
1813 content: "\00A0\25BC";
1814 font-size: 12px;
1814 font-size: 12px;
1815 color: @grey4;
1815 color: @grey4;
1816 }
1816 }
1817
1817
1818 /*new binary
1818 /*new binary
1819 NEW_FILENODE = 1
1819 NEW_FILENODE = 1
1820 DEL_FILENODE = 2
1820 DEL_FILENODE = 2
1821 MOD_FILENODE = 3
1821 MOD_FILENODE = 3
1822 RENAMED_FILENODE = 4
1822 RENAMED_FILENODE = 4
1823 COPIED_FILENODE = 5
1823 COPIED_FILENODE = 5
1824 CHMOD_FILENODE = 6
1824 CHMOD_FILENODE = 6
1825 BIN_FILENODE = 7
1825 BIN_FILENODE = 7
1826 */
1826 */
1827 .cs_files_expand {
1827 .cs_files_expand {
1828 font-size: @basefontsize + 5px;
1828 font-size: @basefontsize + 5px;
1829 line-height: 1.8em;
1829 line-height: 1.8em;
1830 float: right;
1830 float: right;
1831 }
1831 }
1832
1832
1833 .cs_files_expand span{
1833 .cs_files_expand span{
1834 color: @rcblue;
1834 color: @rcblue;
1835 cursor: pointer;
1835 cursor: pointer;
1836 }
1836 }
1837 .cs_files {
1837 .cs_files {
1838 clear: both;
1838 clear: both;
1839 padding-bottom: @padding;
1839 padding-bottom: @padding;
1840
1840
1841 .cur_cs {
1841 .cur_cs {
1842 margin: 10px 2px;
1842 margin: 10px 2px;
1843 font-weight: bold;
1843 font-weight: bold;
1844 }
1844 }
1845
1845
1846 .node {
1846 .node {
1847 float: left;
1847 float: left;
1848 }
1848 }
1849
1849
1850 .changes {
1850 .changes {
1851 float: right;
1851 float: right;
1852 color: white;
1852 color: white;
1853 font-size: @basefontsize - 4px;
1853 font-size: @basefontsize - 4px;
1854 margin-top: 4px;
1854 margin-top: 4px;
1855 opacity: 0.6;
1855 opacity: 0.6;
1856 filter: Alpha(opacity=60); /* IE8 and earlier */
1856 filter: Alpha(opacity=60); /* IE8 and earlier */
1857
1857
1858 .added {
1858 .added {
1859 background-color: @alert1;
1859 background-color: @alert1;
1860 float: left;
1860 float: left;
1861 text-align: center;
1861 text-align: center;
1862 }
1862 }
1863
1863
1864 .deleted {
1864 .deleted {
1865 background-color: @alert2;
1865 background-color: @alert2;
1866 float: left;
1866 float: left;
1867 text-align: center;
1867 text-align: center;
1868 }
1868 }
1869
1869
1870 .bin {
1870 .bin {
1871 background-color: @alert1;
1871 background-color: @alert1;
1872 text-align: center;
1872 text-align: center;
1873 }
1873 }
1874
1874
1875 /*new binary*/
1875 /*new binary*/
1876 .bin.bin1 {
1876 .bin.bin1 {
1877 background-color: @alert1;
1877 background-color: @alert1;
1878 text-align: center;
1878 text-align: center;
1879 }
1879 }
1880
1880
1881 /*deleted binary*/
1881 /*deleted binary*/
1882 .bin.bin2 {
1882 .bin.bin2 {
1883 background-color: @alert2;
1883 background-color: @alert2;
1884 text-align: center;
1884 text-align: center;
1885 }
1885 }
1886
1886
1887 /*mod binary*/
1887 /*mod binary*/
1888 .bin.bin3 {
1888 .bin.bin3 {
1889 background-color: @grey2;
1889 background-color: @grey2;
1890 text-align: center;
1890 text-align: center;
1891 }
1891 }
1892
1892
1893 /*rename file*/
1893 /*rename file*/
1894 .bin.bin4 {
1894 .bin.bin4 {
1895 background-color: @alert4;
1895 background-color: @alert4;
1896 text-align: center;
1896 text-align: center;
1897 }
1897 }
1898
1898
1899 /*copied file*/
1899 /*copied file*/
1900 .bin.bin5 {
1900 .bin.bin5 {
1901 background-color: @alert4;
1901 background-color: @alert4;
1902 text-align: center;
1902 text-align: center;
1903 }
1903 }
1904
1904
1905 /*chmod file*/
1905 /*chmod file*/
1906 .bin.bin6 {
1906 .bin.bin6 {
1907 background-color: @grey2;
1907 background-color: @grey2;
1908 text-align: center;
1908 text-align: center;
1909 }
1909 }
1910 }
1910 }
1911 }
1911 }
1912
1912
1913 .cs_files .cs_added, .cs_files .cs_A,
1913 .cs_files .cs_added, .cs_files .cs_A,
1914 .cs_files .cs_added, .cs_files .cs_M,
1914 .cs_files .cs_added, .cs_files .cs_M,
1915 .cs_files .cs_added, .cs_files .cs_D {
1915 .cs_files .cs_added, .cs_files .cs_D {
1916 height: 16px;
1916 height: 16px;
1917 padding-right: 10px;
1917 padding-right: 10px;
1918 margin-top: 7px;
1918 margin-top: 7px;
1919 text-align: left;
1919 text-align: left;
1920 }
1920 }
1921
1921
1922 .cs_icon_td {
1922 .cs_icon_td {
1923 min-width: 16px;
1923 min-width: 16px;
1924 width: 16px;
1924 width: 16px;
1925 }
1925 }
1926
1926
1927 .pull-request-merge {
1927 .pull-request-merge {
1928 border: 1px solid @grey5;
1928 border: 1px solid @grey5;
1929 padding: 10px 0px 20px;
1929 padding: 10px 0px 20px;
1930 margin-top: 10px;
1930 margin-top: 10px;
1931 margin-bottom: 20px;
1931 margin-bottom: 20px;
1932 }
1932 }
1933
1933
1934 .pull-request-merge-refresh {
1934 .pull-request-merge-refresh {
1935 margin: 2px 7px;
1935 margin: 2px 7px;
1936 a {
1936 a {
1937 color: @grey3;
1937 color: @grey3;
1938 }
1938 }
1939 }
1939 }
1940
1940
1941 .pull-request-merge ul {
1941 .pull-request-merge ul {
1942 padding: 0px 0px;
1942 padding: 0px 0px;
1943 }
1943 }
1944
1944
1945 .pull-request-merge li {
1945 .pull-request-merge li {
1946 list-style-type: none;
1946 list-style-type: none;
1947 }
1947 }
1948
1948
1949 .pull-request-merge .pull-request-wrap {
1949 .pull-request-merge .pull-request-wrap {
1950 height: auto;
1950 height: auto;
1951 padding: 0px 0px;
1951 padding: 0px 0px;
1952 text-align: right;
1952 text-align: right;
1953 }
1953 }
1954
1954
1955 .pull-request-merge span {
1955 .pull-request-merge span {
1956 margin-right: 5px;
1956 margin-right: 5px;
1957 }
1957 }
1958
1958
1959 .pull-request-merge-actions {
1959 .pull-request-merge-actions {
1960 min-height: 30px;
1960 min-height: 30px;
1961 padding: 0px 0px;
1961 padding: 0px 0px;
1962 }
1962 }
1963
1963
1964 .pull-request-merge-info {
1964 .pull-request-merge-info {
1965 padding: 0px 5px 5px 0px;
1965 padding: 0px 5px 5px 0px;
1966 }
1966 }
1967
1967
1968 .merge-status {
1968 .merge-status {
1969 margin-right: 5px;
1969 margin-right: 5px;
1970 }
1970 }
1971
1971
1972 .merge-message {
1972 .merge-message {
1973 font-size: 1.2em
1973 font-size: 1.2em
1974 }
1974 }
1975
1975
1976 .merge-message.success i,
1976 .merge-message.success i,
1977 .merge-icon.success i {
1977 .merge-icon.success i {
1978 color:@alert1;
1978 color:@alert1;
1979 }
1979 }
1980
1980
1981 .merge-message.warning i,
1981 .merge-message.warning i,
1982 .merge-icon.warning i {
1982 .merge-icon.warning i {
1983 color: @alert3;
1983 color: @alert3;
1984 }
1984 }
1985
1985
1986 .merge-message.error i,
1986 .merge-message.error i,
1987 .merge-icon.error i {
1987 .merge-icon.error i {
1988 color:@alert2;
1988 color:@alert2;
1989 }
1989 }
1990
1990
1991 .pr-versions {
1991 .pr-versions {
1992 font-size: 1.1em;
1992 font-size: 1.1em;
1993 padding: 7.5px;
1993 padding: 7.5px;
1994
1994
1995 table {
1995 table {
1996
1996
1997 }
1997 }
1998
1998
1999 td {
1999 td {
2000 line-height: 15px;
2000 line-height: 15px;
2001 }
2001 }
2002
2002
2003 .compare-radio-button {
2003 .compare-radio-button {
2004 position: relative;
2004 position: relative;
2005 top: -3px;
2005 top: -3px;
2006 }
2006 }
2007 }
2007 }
2008
2008
2009
2009
2010 #close_pull_request {
2010 #close_pull_request {
2011 margin-right: 0px;
2011 margin-right: 0px;
2012 }
2012 }
2013
2013
2014 .empty_data {
2014 .empty_data {
2015 color: @grey4;
2015 color: @grey4;
2016 }
2016 }
2017
2017
2018 #changeset_compare_view_content {
2018 #changeset_compare_view_content {
2019 clear: both;
2019 clear: both;
2020 width: 100%;
2020 width: 100%;
2021 box-sizing: border-box;
2021 box-sizing: border-box;
2022 .border-radius(@border-radius);
2022 .border-radius(@border-radius);
2023
2023
2024 .help-block {
2024 .help-block {
2025 margin: @padding 0;
2025 margin: @padding 0;
2026 color: @text-color;
2026 color: @text-color;
2027 &.pre-formatting {
2027 &.pre-formatting {
2028 white-space: pre;
2028 white-space: pre;
2029 }
2029 }
2030 }
2030 }
2031
2031
2032 .empty_data {
2032 .empty_data {
2033 margin: @padding 0;
2033 margin: @padding 0;
2034 }
2034 }
2035
2035
2036 .alert {
2036 .alert {
2037 margin-bottom: @space;
2037 margin-bottom: @space;
2038 }
2038 }
2039 }
2039 }
2040
2040
2041 .table_disp {
2041 .table_disp {
2042 .status {
2042 .status {
2043 width: auto;
2043 width: auto;
2044 }
2044 }
2045 }
2045 }
2046
2046
2047
2047
2048 .creation_in_progress {
2048 .creation_in_progress {
2049 color: @grey4
2049 color: @grey4
2050 }
2050 }
2051
2051
2052 .status_box_menu {
2052 .status_box_menu {
2053 margin: 0;
2053 margin: 0;
2054 }
2054 }
2055
2055
2056 .notification-table{
2056 .notification-table{
2057 margin-bottom: @space;
2057 margin-bottom: @space;
2058 display: table;
2058 display: table;
2059 width: 100%;
2059 width: 100%;
2060
2060
2061 .container{
2061 .container{
2062 display: table-row;
2062 display: table-row;
2063
2063
2064 .notification-header{
2064 .notification-header{
2065 border-bottom: @border-thickness solid @border-default-color;
2065 border-bottom: @border-thickness solid @border-default-color;
2066 }
2066 }
2067
2067
2068 .notification-subject{
2068 .notification-subject{
2069 display: table-cell;
2069 display: table-cell;
2070 }
2070 }
2071 }
2071 }
2072 }
2072 }
2073
2073
2074 // Notifications
2074 // Notifications
2075 .notification-header{
2075 .notification-header{
2076 display: table;
2076 display: table;
2077 width: 100%;
2077 width: 100%;
2078 padding: floor(@basefontsize/2) 0;
2078 padding: floor(@basefontsize/2) 0;
2079 line-height: 1em;
2079 line-height: 1em;
2080
2080
2081 .desc, .delete-notifications, .read-notifications{
2081 .desc, .delete-notifications, .read-notifications{
2082 display: table-cell;
2082 display: table-cell;
2083 text-align: left;
2083 text-align: left;
2084 }
2084 }
2085
2085
2086 .delete-notifications, .read-notifications{
2086 .delete-notifications, .read-notifications{
2087 width: 35px;
2087 width: 35px;
2088 min-width: 35px; //fixes when only one button is displayed
2088 min-width: 35px; //fixes when only one button is displayed
2089 }
2089 }
2090 }
2090 }
2091
2091
2092 .notification-body {
2092 .notification-body {
2093 .markdown-block,
2093 .markdown-block,
2094 .rst-block {
2094 .rst-block {
2095 padding: @padding 0;
2095 padding: @padding 0;
2096 }
2096 }
2097
2097
2098 .notification-subject {
2098 .notification-subject {
2099 padding: @textmargin 0;
2099 padding: @textmargin 0;
2100 border-bottom: @border-thickness solid @border-default-color;
2100 border-bottom: @border-thickness solid @border-default-color;
2101 }
2101 }
2102 }
2102 }
2103
2103
2104 .notice-messages {
2104 .notice-messages {
2105 .markdown-block,
2105 .markdown-block,
2106 .rst-block {
2106 .rst-block {
2107 padding: 0;
2107 padding: 0;
2108 }
2108 }
2109 }
2109 }
2110
2110
2111 .notifications_buttons{
2111 .notifications_buttons{
2112 float: right;
2112 float: right;
2113 }
2113 }
2114
2114
2115 #notification-status{
2115 #notification-status{
2116 display: inline;
2116 display: inline;
2117 }
2117 }
2118
2118
2119 // Repositories
2119 // Repositories
2120
2120
2121 #summary.fields{
2121 #summary.fields{
2122 display: table;
2122 display: table;
2123
2123
2124 .field{
2124 .field{
2125 display: table-row;
2125 display: table-row;
2126
2126
2127 .label-summary{
2127 .label-summary{
2128 display: table-cell;
2128 display: table-cell;
2129 min-width: @label-summary-minwidth;
2129 min-width: @label-summary-minwidth;
2130 padding-top: @padding/2;
2130 padding-top: @padding/2;
2131 padding-bottom: @padding/2;
2131 padding-bottom: @padding/2;
2132 padding-right: @padding/2;
2132 padding-right: @padding/2;
2133 }
2133 }
2134
2134
2135 .input{
2135 .input{
2136 display: table-cell;
2136 display: table-cell;
2137 padding: @padding/2;
2137 padding: @padding/2;
2138
2138
2139 input{
2139 input{
2140 min-width: 29em;
2140 min-width: 29em;
2141 padding: @padding/4;
2141 padding: @padding/4;
2142 }
2142 }
2143 }
2143 }
2144 .statistics, .downloads{
2144 .statistics, .downloads{
2145 .disabled{
2145 .disabled{
2146 color: @grey4;
2146 color: @grey4;
2147 }
2147 }
2148 }
2148 }
2149 }
2149 }
2150 }
2150 }
2151
2151
2152 #summary{
2152 #summary{
2153 width: 70%;
2153 width: 70%;
2154 }
2154 }
2155
2155
2156
2156
2157 // Journal
2157 // Journal
2158 .journal.title {
2158 .journal.title {
2159 h5 {
2159 h5 {
2160 float: left;
2160 float: left;
2161 margin: 0;
2161 margin: 0;
2162 width: 70%;
2162 width: 70%;
2163 }
2163 }
2164
2164
2165 ul {
2165 ul {
2166 float: right;
2166 float: right;
2167 display: inline-block;
2167 display: inline-block;
2168 margin: 0;
2168 margin: 0;
2169 width: 30%;
2169 width: 30%;
2170 text-align: right;
2170 text-align: right;
2171
2171
2172 li {
2172 li {
2173 display: inline;
2173 display: inline;
2174 font-size: @journal-fontsize;
2174 font-size: @journal-fontsize;
2175 line-height: 1em;
2175 line-height: 1em;
2176
2176
2177 list-style-type: none;
2177 list-style-type: none;
2178 }
2178 }
2179 }
2179 }
2180 }
2180 }
2181
2181
2182 .filterexample {
2182 .filterexample {
2183 position: absolute;
2183 position: absolute;
2184 top: 95px;
2184 top: 95px;
2185 left: @contentpadding;
2185 left: @contentpadding;
2186 color: @rcblue;
2186 color: @rcblue;
2187 font-size: 11px;
2187 font-size: 11px;
2188 font-family: @text-regular;
2188 font-family: @text-regular;
2189 cursor: help;
2189 cursor: help;
2190
2190
2191 &:hover {
2191 &:hover {
2192 color: @rcdarkblue;
2192 color: @rcdarkblue;
2193 }
2193 }
2194
2194
2195 @media (max-width:768px) {
2195 @media (max-width:768px) {
2196 position: relative;
2196 position: relative;
2197 top: auto;
2197 top: auto;
2198 left: auto;
2198 left: auto;
2199 display: block;
2199 display: block;
2200 }
2200 }
2201 }
2201 }
2202
2202
2203
2203
2204 #journal{
2204 #journal{
2205 margin-bottom: @space;
2205 margin-bottom: @space;
2206
2206
2207 .journal_day{
2207 .journal_day{
2208 margin-bottom: @textmargin/2;
2208 margin-bottom: @textmargin/2;
2209 padding-bottom: @textmargin/2;
2209 padding-bottom: @textmargin/2;
2210 font-size: @journal-fontsize;
2210 font-size: @journal-fontsize;
2211 border-bottom: @border-thickness solid @border-default-color;
2211 border-bottom: @border-thickness solid @border-default-color;
2212 }
2212 }
2213
2213
2214 .journal_container{
2214 .journal_container{
2215 margin-bottom: @space;
2215 margin-bottom: @space;
2216
2216
2217 .journal_user{
2217 .journal_user{
2218 display: inline-block;
2218 display: inline-block;
2219 }
2219 }
2220 .journal_action_container{
2220 .journal_action_container{
2221 display: block;
2221 display: block;
2222 margin-top: @textmargin;
2222 margin-top: @textmargin;
2223
2223
2224 div{
2224 div{
2225 display: inline;
2225 display: inline;
2226 }
2226 }
2227
2227
2228 div.journal_action_params{
2228 div.journal_action_params{
2229 display: block;
2229 display: block;
2230 }
2230 }
2231
2231
2232 div.journal_repo:after{
2232 div.journal_repo:after{
2233 content: "\A";
2233 content: "\A";
2234 white-space: pre;
2234 white-space: pre;
2235 }
2235 }
2236
2236
2237 div.date{
2237 div.date{
2238 display: block;
2238 display: block;
2239 margin-bottom: @textmargin;
2239 margin-bottom: @textmargin;
2240 }
2240 }
2241 }
2241 }
2242 }
2242 }
2243 }
2243 }
2244
2244
2245 // Files
2245 // Files
2246 .edit-file-title {
2246 .edit-file-title {
2247 font-size: 16px;
2247 font-size: 16px;
2248
2248
2249 .title-heading {
2249 .title-heading {
2250 padding: 2px;
2250 padding: 2px;
2251 }
2251 }
2252 }
2252 }
2253
2253
2254 .edit-file-fieldset {
2254 .edit-file-fieldset {
2255 margin: @sidebarpadding 0;
2255 margin: @sidebarpadding 0;
2256
2256
2257 .fieldset {
2257 .fieldset {
2258 .left-label {
2258 .left-label {
2259 width: 13%;
2259 width: 13%;
2260 }
2260 }
2261 .right-content {
2261 .right-content {
2262 width: 87%;
2262 width: 87%;
2263 max-width: 100%;
2263 max-width: 100%;
2264 }
2264 }
2265 .filename-label {
2265 .filename-label {
2266 margin-top: 13px;
2266 margin-top: 13px;
2267 }
2267 }
2268 .commit-message-label {
2268 .commit-message-label {
2269 margin-top: 4px;
2269 margin-top: 4px;
2270 }
2270 }
2271 .file-upload-input {
2271 .file-upload-input {
2272 input {
2272 input {
2273 display: none;
2273 display: none;
2274 }
2274 }
2275 margin-top: 10px;
2275 margin-top: 10px;
2276 }
2276 }
2277 .file-upload-label {
2277 .file-upload-label {
2278 margin-top: 10px;
2278 margin-top: 10px;
2279 }
2279 }
2280 p {
2280 p {
2281 margin-top: 5px;
2281 margin-top: 5px;
2282 }
2282 }
2283
2283
2284 }
2284 }
2285 .custom-path-link {
2285 .custom-path-link {
2286 margin-left: 5px;
2286 margin-left: 5px;
2287 }
2287 }
2288 #commit {
2288 #commit {
2289 resize: vertical;
2289 resize: vertical;
2290 }
2290 }
2291 }
2291 }
2292
2292
2293 .delete-file-preview {
2293 .delete-file-preview {
2294 max-height: 250px;
2294 max-height: 250px;
2295 }
2295 }
2296
2296
2297 .new-file,
2297 .new-file,
2298 #filter_activate,
2298 #filter_activate,
2299 #filter_deactivate {
2299 #filter_deactivate {
2300 float: right;
2300 float: right;
2301 margin: 0 0 0 10px;
2301 margin: 0 0 0 10px;
2302 }
2302 }
2303
2303
2304 .file-upload-transaction-wrapper {
2304 .file-upload-transaction-wrapper {
2305 margin-top: 57px;
2305 margin-top: 57px;
2306 clear: both;
2306 clear: both;
2307 }
2307 }
2308
2308
2309 .file-upload-transaction-wrapper .error {
2309 .file-upload-transaction-wrapper .error {
2310 color: @color5;
2310 color: @color5;
2311 }
2311 }
2312
2312
2313 .file-upload-transaction {
2313 .file-upload-transaction {
2314 min-height: 200px;
2314 min-height: 200px;
2315 padding: 54px;
2315 padding: 54px;
2316 border: 1px solid @grey5;
2316 border: 1px solid @grey5;
2317 text-align: center;
2317 text-align: center;
2318 clear: both;
2318 clear: both;
2319 }
2319 }
2320
2320
2321 .file-upload-transaction i {
2321 .file-upload-transaction i {
2322 font-size: 48px
2322 font-size: 48px
2323 }
2323 }
2324
2324
2325 h3.files_location{
2325 h3.files_location{
2326 line-height: 2.4em;
2326 line-height: 2.4em;
2327 }
2327 }
2328
2328
2329 .browser-nav {
2329 .browser-nav {
2330 width: 100%;
2330 width: 100%;
2331 display: table;
2331 display: table;
2332 margin-bottom: 20px;
2332 margin-bottom: 20px;
2333
2333
2334 .info_box {
2334 .info_box {
2335 float: left;
2335 float: left;
2336 display: inline-table;
2336 display: inline-table;
2337 height: 2.5em;
2337 height: 2.5em;
2338
2338
2339 .browser-cur-rev, .info_box_elem {
2339 .browser-cur-rev, .info_box_elem {
2340 display: table-cell;
2340 display: table-cell;
2341 vertical-align: middle;
2341 vertical-align: middle;
2342 }
2342 }
2343
2343
2344 .drop-menu {
2344 .drop-menu {
2345 margin: 0 10px;
2345 margin: 0 10px;
2346 }
2346 }
2347
2347
2348 .info_box_elem {
2348 .info_box_elem {
2349 border-top: @border-thickness solid @grey5;
2349 border-top: @border-thickness solid @grey5;
2350 border-bottom: @border-thickness solid @grey5;
2350 border-bottom: @border-thickness solid @grey5;
2351 box-shadow: @button-shadow;
2351 box-shadow: @button-shadow;
2352
2352
2353 #at_rev, a {
2353 #at_rev, a {
2354 padding: 0.6em 0.4em;
2354 padding: 0.6em 0.4em;
2355 margin: 0;
2355 margin: 0;
2356 .box-shadow(none);
2356 .box-shadow(none);
2357 border: 0;
2357 border: 0;
2358 height: 12px;
2358 height: 12px;
2359 color: @grey2;
2359 color: @grey2;
2360 }
2360 }
2361
2361
2362 input#at_rev {
2362 input#at_rev {
2363 max-width: 50px;
2363 max-width: 50px;
2364 text-align: center;
2364 text-align: center;
2365 }
2365 }
2366
2366
2367 &.previous {
2367 &.previous {
2368 border: @border-thickness solid @grey5;
2368 border: @border-thickness solid @grey5;
2369 border-top-left-radius: @border-radius;
2369 border-top-left-radius: @border-radius;
2370 border-bottom-left-radius: @border-radius;
2370 border-bottom-left-radius: @border-radius;
2371
2371
2372 &:hover {
2372 &:hover {
2373 border-color: @grey4;
2373 border-color: @grey4;
2374 }
2374 }
2375
2375
2376 .disabled {
2376 .disabled {
2377 color: @grey5;
2377 color: @grey5;
2378 cursor: not-allowed;
2378 cursor: not-allowed;
2379 opacity: 0.5;
2379 opacity: 0.5;
2380 }
2380 }
2381 }
2381 }
2382
2382
2383 &.next {
2383 &.next {
2384 border: @border-thickness solid @grey5;
2384 border: @border-thickness solid @grey5;
2385 border-top-right-radius: @border-radius;
2385 border-top-right-radius: @border-radius;
2386 border-bottom-right-radius: @border-radius;
2386 border-bottom-right-radius: @border-radius;
2387
2387
2388 &:hover {
2388 &:hover {
2389 border-color: @grey4;
2389 border-color: @grey4;
2390 }
2390 }
2391
2391
2392 .disabled {
2392 .disabled {
2393 color: @grey5;
2393 color: @grey5;
2394 cursor: not-allowed;
2394 cursor: not-allowed;
2395 opacity: 0.5;
2395 opacity: 0.5;
2396 }
2396 }
2397 }
2397 }
2398 }
2398 }
2399
2399
2400 .browser-cur-rev {
2400 .browser-cur-rev {
2401
2401
2402 span{
2402 span{
2403 margin: 0;
2403 margin: 0;
2404 color: @rcblue;
2404 color: @rcblue;
2405 height: 12px;
2405 height: 12px;
2406 display: inline-block;
2406 display: inline-block;
2407 padding: 0.7em 1em ;
2407 padding: 0.7em 1em ;
2408 border: @border-thickness solid @rcblue;
2408 border: @border-thickness solid @rcblue;
2409 margin-right: @padding;
2409 margin-right: @padding;
2410 }
2410 }
2411 }
2411 }
2412
2412
2413 }
2413 }
2414
2414
2415 .select-index-number {
2415 .select-index-number {
2416 margin: 0 0 0 20px;
2416 margin: 0 0 0 20px;
2417 color: @grey3;
2417 color: @grey3;
2418 }
2418 }
2419
2419
2420 .search_activate {
2420 .search_activate {
2421 display: table-cell;
2421 display: table-cell;
2422 vertical-align: middle;
2422 vertical-align: middle;
2423
2423
2424 input, label{
2424 input, label{
2425 margin: 0;
2425 margin: 0;
2426 padding: 0;
2426 padding: 0;
2427 }
2427 }
2428
2428
2429 input{
2429 input{
2430 margin-left: @textmargin;
2430 margin-left: @textmargin;
2431 }
2431 }
2432
2432
2433 }
2433 }
2434 }
2434 }
2435
2435
2436 .browser-cur-rev{
2436 .browser-cur-rev{
2437 margin-bottom: @textmargin;
2437 margin-bottom: @textmargin;
2438 }
2438 }
2439
2439
2440 #node_filter_box_loading{
2440 #node_filter_box_loading{
2441 .info_text;
2441 .info_text;
2442 }
2442 }
2443
2443
2444 .browser-search {
2444 .browser-search {
2445 margin: -25px 0px 5px 0px;
2445 margin: -25px 0px 5px 0px;
2446 }
2446 }
2447
2447
2448 .files-quick-filter {
2448 .files-quick-filter {
2449 float: right;
2449 float: right;
2450 width: 180px;
2450 width: 180px;
2451 position: relative;
2451 position: relative;
2452 }
2452 }
2453
2453
2454 .files-filter-box {
2454 .files-filter-box {
2455 display: flex;
2455 display: flex;
2456 padding: 0px;
2456 padding: 0px;
2457 border-radius: 3px;
2457 border-radius: 3px;
2458 margin-bottom: 0;
2458 margin-bottom: 0;
2459
2459
2460 a {
2460 a {
2461 border: none !important;
2461 border: none !important;
2462 }
2462 }
2463
2463
2464 li {
2464 li {
2465 list-style-type: none
2465 list-style-type: none
2466 }
2466 }
2467 }
2467 }
2468
2468
2469 .files-filter-box-path {
2469 .files-filter-box-path {
2470 line-height: 33px;
2470 line-height: 33px;
2471 padding: 0;
2471 padding: 0;
2472 width: 20px;
2472 width: 20px;
2473 position: absolute;
2473 position: absolute;
2474 z-index: 11;
2474 z-index: 11;
2475 left: 5px;
2475 left: 5px;
2476 }
2476 }
2477
2477
2478 .files-filter-box-input {
2478 .files-filter-box-input {
2479 margin-right: 0;
2479 margin-right: 0;
2480
2480
2481 input {
2481 input {
2482 border: 1px solid @white;
2482 border: 1px solid @white;
2483 padding-left: 25px;
2483 padding-left: 25px;
2484 width: 145px;
2484 width: 145px;
2485
2485
2486 &:hover {
2486 &:hover {
2487 border-color: @grey6;
2487 border-color: @grey6;
2488 }
2488 }
2489
2489
2490 &:focus {
2490 &:focus {
2491 border-color: @grey5;
2491 border-color: @grey5;
2492 }
2492 }
2493 }
2493 }
2494 }
2494 }
2495
2495
2496 .browser-result{
2496 .browser-result{
2497 td a{
2497 td a{
2498 margin-left: 0.5em;
2498 margin-left: 0.5em;
2499 display: inline-block;
2499 display: inline-block;
2500
2500
2501 em {
2501 em {
2502 font-weight: @text-bold-weight;
2502 font-weight: @text-bold-weight;
2503 font-family: @text-bold;
2503 font-family: @text-bold;
2504 }
2504 }
2505 }
2505 }
2506 }
2506 }
2507
2507
2508 .browser-highlight{
2508 .browser-highlight{
2509 background-color: @grey5-alpha;
2509 background-color: @grey5-alpha;
2510 }
2510 }
2511
2511
2512
2512
2513 .edit-file-fieldset #location,
2513 .edit-file-fieldset #location,
2514 .edit-file-fieldset #filename {
2514 .edit-file-fieldset #filename {
2515 display: flex;
2515 display: flex;
2516 width: -moz-available; /* WebKit-based browsers will ignore this. */
2516 width: -moz-available; /* WebKit-based browsers will ignore this. */
2517 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2517 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2518 width: fill-available;
2518 width: fill-available;
2519 border: 0;
2519 border: 0;
2520 }
2520 }
2521
2521
2522 .path-items {
2522 .path-items {
2523 display: flex;
2523 display: flex;
2524 padding: 0;
2524 padding: 0;
2525 border: 1px solid #eeeeee;
2525 border: 1px solid #eeeeee;
2526 width: 100%;
2526 width: 100%;
2527 float: left;
2527 float: left;
2528
2528
2529 .breadcrumb-path {
2529 .breadcrumb-path {
2530 line-height: 30px;
2530 line-height: 30px;
2531 padding: 0 4px;
2531 padding: 0 4px;
2532 white-space: nowrap;
2532 white-space: nowrap;
2533 }
2533 }
2534
2534
2535 .upload-form {
2536 margin-top: 46px;
2537 }
2538
2535 .location-path {
2539 .location-path {
2536 width: -moz-available; /* WebKit-based browsers will ignore this. */
2540 width: -moz-available; /* WebKit-based browsers will ignore this. */
2537 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2541 width: -webkit-fill-available; /* Mozilla-based browsers will ignore this. */
2538 width: fill-available;
2542 width: fill-available;
2539
2543
2540 .file-name-input {
2544 .file-name-input {
2541 padding: 0.5em 0;
2545 padding: 0.5em 0;
2542 }
2546 }
2543
2547
2544 }
2548 }
2545
2549
2546 ul {
2550 ul {
2547 display: flex;
2551 display: flex;
2548 margin: 0;
2552 margin: 0;
2549 padding: 0;
2553 padding: 0;
2550 width: 100%;
2554 width: 100%;
2551 }
2555 }
2552
2556
2553 li {
2557 li {
2554 list-style-type: none;
2558 list-style-type: none;
2555 }
2559 }
2556
2560
2557 }
2561 }
2558
2562
2559 .editor-items {
2563 .editor-items {
2560 height: 40px;
2564 height: 40px;
2561 margin: 10px 0 -17px 10px;
2565 margin: 10px 0 -17px 10px;
2562
2566
2563 .editor-action {
2567 .editor-action {
2564 cursor: pointer;
2568 cursor: pointer;
2565 }
2569 }
2566
2570
2567 .editor-action.active {
2571 .editor-action.active {
2568 border-bottom: 2px solid #5C5C5C;
2572 border-bottom: 2px solid #5C5C5C;
2569 }
2573 }
2570
2574
2571 li {
2575 li {
2572 list-style-type: none;
2576 list-style-type: none;
2573 }
2577 }
2574 }
2578 }
2575
2579
2576 .edit-file-fieldset .message textarea {
2580 .edit-file-fieldset .message textarea {
2577 border: 1px solid #eeeeee;
2581 border: 1px solid #eeeeee;
2578 }
2582 }
2579
2583
2580 #files_data .codeblock {
2584 #files_data .codeblock {
2581 background-color: #F5F5F5;
2585 background-color: #F5F5F5;
2582 }
2586 }
2583
2587
2584 #editor_preview {
2588 #editor_preview {
2585 background: white;
2589 background: white;
2586 }
2590 }
2587
2591
2588 .show-editor {
2592 .show-editor {
2589 padding: 10px;
2593 padding: 10px;
2590 background-color: white;
2594 background-color: white;
2591
2595
2592 }
2596 }
2593
2597
2594 .show-preview {
2598 .show-preview {
2595 padding: 10px;
2599 padding: 10px;
2596 background-color: white;
2600 background-color: white;
2597 border-left: 1px solid #eeeeee;
2601 border-left: 1px solid #eeeeee;
2598 }
2602 }
2599 // quick filter
2603 // quick filter
2600 .grid-quick-filter {
2604 .grid-quick-filter {
2601 float: right;
2605 float: right;
2602 position: relative;
2606 position: relative;
2603 }
2607 }
2604
2608
2605 .grid-filter-box {
2609 .grid-filter-box {
2606 display: flex;
2610 display: flex;
2607 padding: 0px;
2611 padding: 0px;
2608 border-radius: 3px;
2612 border-radius: 3px;
2609 margin-bottom: 0;
2613 margin-bottom: 0;
2610
2614
2611 a {
2615 a {
2612 border: none !important;
2616 border: none !important;
2613 }
2617 }
2614
2618
2615 li {
2619 li {
2616 list-style-type: none
2620 list-style-type: none
2617 }
2621 }
2618 }
2622 }
2619
2623
2620 .grid-filter-box-icon {
2624 .grid-filter-box-icon {
2621 line-height: 33px;
2625 line-height: 33px;
2622 padding: 0;
2626 padding: 0;
2623 width: 20px;
2627 width: 20px;
2624 position: absolute;
2628 position: absolute;
2625 z-index: 11;
2629 z-index: 11;
2626 left: 5px;
2630 left: 5px;
2627 }
2631 }
2628
2632
2629 .grid-filter-box-input {
2633 .grid-filter-box-input {
2630 margin-right: 0;
2634 margin-right: 0;
2631
2635
2632 input {
2636 input {
2633 border: 1px solid @white;
2637 border: 1px solid @white;
2634 padding-left: 25px;
2638 padding-left: 25px;
2635 width: 145px;
2639 width: 145px;
2636
2640
2637 &:hover {
2641 &:hover {
2638 border-color: @grey6;
2642 border-color: @grey6;
2639 }
2643 }
2640
2644
2641 &:focus {
2645 &:focus {
2642 border-color: @grey5;
2646 border-color: @grey5;
2643 }
2647 }
2644 }
2648 }
2645 }
2649 }
2646
2650
2647
2651
2648
2652
2649 // Search
2653 // Search
2650
2654
2651 .search-form{
2655 .search-form{
2652 #q {
2656 #q {
2653 width: @search-form-width;
2657 width: @search-form-width;
2654 }
2658 }
2655 .fields{
2659 .fields{
2656 margin: 0 0 @space;
2660 margin: 0 0 @space;
2657 }
2661 }
2658
2662
2659 label{
2663 label{
2660 display: inline-block;
2664 display: inline-block;
2661 margin-right: @textmargin;
2665 margin-right: @textmargin;
2662 padding-top: 0.25em;
2666 padding-top: 0.25em;
2663 }
2667 }
2664
2668
2665
2669
2666 .results{
2670 .results{
2667 clear: both;
2671 clear: both;
2668 margin: 0 0 @padding;
2672 margin: 0 0 @padding;
2669 }
2673 }
2670
2674
2671 .search-tags {
2675 .search-tags {
2672 padding: 5px 0;
2676 padding: 5px 0;
2673 }
2677 }
2674 }
2678 }
2675
2679
2676 div.search-feedback-items {
2680 div.search-feedback-items {
2677 display: inline-block;
2681 display: inline-block;
2678 }
2682 }
2679
2683
2680 div.search-code-body {
2684 div.search-code-body {
2681 background-color: #ffffff; padding: 5px 0 5px 10px;
2685 background-color: #ffffff; padding: 5px 0 5px 10px;
2682 pre {
2686 pre {
2683 .match { background-color: #faffa6;}
2687 .match { background-color: #faffa6;}
2684 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2688 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2685 }
2689 }
2686 }
2690 }
2687
2691
2688 .expand_commit.search {
2692 .expand_commit.search {
2689 .show_more.open {
2693 .show_more.open {
2690 height: auto;
2694 height: auto;
2691 max-height: none;
2695 max-height: none;
2692 }
2696 }
2693 }
2697 }
2694
2698
2695 .search-results {
2699 .search-results {
2696
2700
2697 h2 {
2701 h2 {
2698 margin-bottom: 0;
2702 margin-bottom: 0;
2699 }
2703 }
2700 .codeblock {
2704 .codeblock {
2701 border: none;
2705 border: none;
2702 background: transparent;
2706 background: transparent;
2703 }
2707 }
2704
2708
2705 .codeblock-header {
2709 .codeblock-header {
2706 border: none;
2710 border: none;
2707 background: transparent;
2711 background: transparent;
2708 }
2712 }
2709
2713
2710 .code-body {
2714 .code-body {
2711 border: @border-thickness solid @grey6;
2715 border: @border-thickness solid @grey6;
2712 .border-radius(@border-radius);
2716 .border-radius(@border-radius);
2713 }
2717 }
2714
2718
2715 .td-commit {
2719 .td-commit {
2716 &:extend(pre);
2720 &:extend(pre);
2717 border-bottom: @border-thickness solid @border-default-color;
2721 border-bottom: @border-thickness solid @border-default-color;
2718 }
2722 }
2719
2723
2720 .message {
2724 .message {
2721 height: auto;
2725 height: auto;
2722 max-width: 350px;
2726 max-width: 350px;
2723 white-space: normal;
2727 white-space: normal;
2724 text-overflow: initial;
2728 text-overflow: initial;
2725 overflow: visible;
2729 overflow: visible;
2726
2730
2727 .match { background-color: #faffa6;}
2731 .match { background-color: #faffa6;}
2728 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2732 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2729 }
2733 }
2730
2734
2731 .path {
2735 .path {
2732 border-bottom: none !important;
2736 border-bottom: none !important;
2733 border-left: 1px solid @grey6 !important;
2737 border-left: 1px solid @grey6 !important;
2734 border-right: 1px solid @grey6 !important;
2738 border-right: 1px solid @grey6 !important;
2735 }
2739 }
2736 }
2740 }
2737
2741
2738 table.rctable td.td-search-results div {
2742 table.rctable td.td-search-results div {
2739 max-width: 100%;
2743 max-width: 100%;
2740 }
2744 }
2741
2745
2742 #tip-box, .tip-box{
2746 #tip-box, .tip-box{
2743 padding: @menupadding/2;
2747 padding: @menupadding/2;
2744 display: block;
2748 display: block;
2745 border: @border-thickness solid @border-highlight-color;
2749 border: @border-thickness solid @border-highlight-color;
2746 .border-radius(@border-radius);
2750 .border-radius(@border-radius);
2747 background-color: white;
2751 background-color: white;
2748 z-index: 99;
2752 z-index: 99;
2749 white-space: pre-wrap;
2753 white-space: pre-wrap;
2750 }
2754 }
2751
2755
2752 #linktt {
2756 #linktt {
2753 width: 79px;
2757 width: 79px;
2754 }
2758 }
2755
2759
2756 #help_kb .modal-content{
2760 #help_kb .modal-content{
2757 max-width: 750px;
2761 max-width: 750px;
2758 margin: 10% auto;
2762 margin: 10% auto;
2759
2763
2760 table{
2764 table{
2761 td,th{
2765 td,th{
2762 border-bottom: none;
2766 border-bottom: none;
2763 line-height: 2.5em;
2767 line-height: 2.5em;
2764 }
2768 }
2765 th{
2769 th{
2766 padding-bottom: @textmargin/2;
2770 padding-bottom: @textmargin/2;
2767 }
2771 }
2768 td.keys{
2772 td.keys{
2769 text-align: center;
2773 text-align: center;
2770 }
2774 }
2771 }
2775 }
2772
2776
2773 .block-left{
2777 .block-left{
2774 width: 45%;
2778 width: 45%;
2775 margin-right: 5%;
2779 margin-right: 5%;
2776 }
2780 }
2777 .modal-footer{
2781 .modal-footer{
2778 clear: both;
2782 clear: both;
2779 }
2783 }
2780 .key.tag{
2784 .key.tag{
2781 padding: 0.5em;
2785 padding: 0.5em;
2782 background-color: @rcblue;
2786 background-color: @rcblue;
2783 color: white;
2787 color: white;
2784 border-color: @rcblue;
2788 border-color: @rcblue;
2785 .box-shadow(none);
2789 .box-shadow(none);
2786 }
2790 }
2787 }
2791 }
2788
2792
2789
2793
2790
2794
2791 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2795 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2792
2796
2793 @import 'statistics-graph';
2797 @import 'statistics-graph';
2794 @import 'tables';
2798 @import 'tables';
2795 @import 'forms';
2799 @import 'forms';
2796 @import 'diff';
2800 @import 'diff';
2797 @import 'summary';
2801 @import 'summary';
2798 @import 'navigation';
2802 @import 'navigation';
2799
2803
2800 //--- SHOW/HIDE SECTIONS --//
2804 //--- SHOW/HIDE SECTIONS --//
2801
2805
2802 .btn-collapse {
2806 .btn-collapse {
2803 float: right;
2807 float: right;
2804 text-align: right;
2808 text-align: right;
2805 font-family: @text-light;
2809 font-family: @text-light;
2806 font-size: @basefontsize;
2810 font-size: @basefontsize;
2807 cursor: pointer;
2811 cursor: pointer;
2808 border: none;
2812 border: none;
2809 color: @rcblue;
2813 color: @rcblue;
2810 }
2814 }
2811
2815
2812 table.rctable,
2816 table.rctable,
2813 table.dataTable {
2817 table.dataTable {
2814 .btn-collapse {
2818 .btn-collapse {
2815 float: right;
2819 float: right;
2816 text-align: right;
2820 text-align: right;
2817 }
2821 }
2818 }
2822 }
2819
2823
2820 table.rctable {
2824 table.rctable {
2821 &.permissions {
2825 &.permissions {
2822
2826
2823 th.td-owner {
2827 th.td-owner {
2824 padding: 0;
2828 padding: 0;
2825 }
2829 }
2826
2830
2827 th {
2831 th {
2828 font-weight: normal;
2832 font-weight: normal;
2829 padding: 0 5px;
2833 padding: 0 5px;
2830 }
2834 }
2831
2835
2832 }
2836 }
2833 }
2837 }
2834
2838
2835
2839
2836 // TODO: johbo: Fix for IE10, this avoids that we see a border
2840 // TODO: johbo: Fix for IE10, this avoids that we see a border
2837 // and padding around checkboxes and radio boxes. Move to the right place,
2841 // and padding around checkboxes and radio boxes. Move to the right place,
2838 // or better: Remove this once we did the form refactoring.
2842 // or better: Remove this once we did the form refactoring.
2839 input[type=checkbox],
2843 input[type=checkbox],
2840 input[type=radio] {
2844 input[type=radio] {
2841 padding: 0;
2845 padding: 0;
2842 border: none;
2846 border: none;
2843 }
2847 }
2844
2848
2845 .toggle-ajax-spinner{
2849 .toggle-ajax-spinner{
2846 height: 16px;
2850 height: 16px;
2847 width: 16px;
2851 width: 16px;
2848 }
2852 }
2849
2853
2850
2854
2851 .markup-form .clearfix {
2855 .markup-form .clearfix {
2852 .border-radius(@border-radius);
2856 .border-radius(@border-radius);
2853 margin: 0px;
2857 margin: 0px;
2854 }
2858 }
2855
2859
2856 .markup-form-area {
2860 .markup-form-area {
2857 padding: 8px 12px;
2861 padding: 8px 12px;
2858 border: 1px solid @grey4;
2862 border: 1px solid @grey4;
2859 .border-radius(@border-radius);
2863 .border-radius(@border-radius);
2860 }
2864 }
2861
2865
2862 .markup-form-area-header .nav-links {
2866 .markup-form-area-header .nav-links {
2863 display: flex;
2867 display: flex;
2864 flex-flow: row wrap;
2868 flex-flow: row wrap;
2865 -webkit-flex-flow: row wrap;
2869 -webkit-flex-flow: row wrap;
2866 width: 100%;
2870 width: 100%;
2867 }
2871 }
2868
2872
2869 .markup-form-area-footer {
2873 .markup-form-area-footer {
2870 display: flex;
2874 display: flex;
2871 }
2875 }
2872
2876
2873 .markup-form-area-footer .toolbar {
2877 .markup-form-area-footer .toolbar {
2874
2878
2875 }
2879 }
2876
2880
2877 // markup Form
2881 // markup Form
2878 div.markup-form {
2882 div.markup-form {
2879 margin-top: 20px;
2883 margin-top: 20px;
2880 }
2884 }
2881
2885
2882 .markup-form strong {
2886 .markup-form strong {
2883 display: block;
2887 display: block;
2884 margin-bottom: 15px;
2888 margin-bottom: 15px;
2885 }
2889 }
2886
2890
2887 .markup-form textarea {
2891 .markup-form textarea {
2888 width: 100%;
2892 width: 100%;
2889 height: 100px;
2893 height: 100px;
2890 font-family: @text-monospace;
2894 font-family: @text-monospace;
2891 }
2895 }
2892
2896
2893 form.markup-form {
2897 form.markup-form {
2894 margin-top: 10px;
2898 margin-top: 10px;
2895 margin-left: 10px;
2899 margin-left: 10px;
2896 }
2900 }
2897
2901
2898 .markup-form .comment-block-ta,
2902 .markup-form .comment-block-ta,
2899 .markup-form .preview-box {
2903 .markup-form .preview-box {
2900 .border-radius(@border-radius);
2904 .border-radius(@border-radius);
2901 .box-sizing(border-box);
2905 .box-sizing(border-box);
2902 background-color: white;
2906 background-color: white;
2903 }
2907 }
2904
2908
2905 .markup-form .preview-box.unloaded {
2909 .markup-form .preview-box.unloaded {
2906 height: 50px;
2910 height: 50px;
2907 text-align: center;
2911 text-align: center;
2908 padding: 20px;
2912 padding: 20px;
2909 background-color: white;
2913 background-color: white;
2910 }
2914 }
2911
2915
2912
2916
2913 .dropzone-wrapper {
2917 .dropzone-wrapper {
2914 border: 1px solid @grey5;
2918 border: 1px solid @grey5;
2915 padding: 20px;
2919 padding: 20px;
2916 }
2920 }
2917
2921
2918 .dropzone,
2922 .dropzone,
2919 .dropzone-pure {
2923 .dropzone-pure {
2920 border: 2px dashed @grey5;
2924 border: 2px dashed @grey5;
2921 border-radius: 5px;
2925 border-radius: 5px;
2922 background: white;
2926 background: white;
2923 min-height: 200px;
2927 min-height: 200px;
2924 padding: 54px;
2928 padding: 54px;
2925
2929
2926 .dz-message {
2930 .dz-message {
2927 font-weight: 700;
2931 font-weight: 700;
2928 text-align: center;
2932 text-align: center;
2929 margin: 2em 0;
2933 margin: 2em 0;
2930 }
2934 }
2931
2935
2932 }
2936 }
2933
2937
2934 .dz-preview {
2938 .dz-preview {
2935 margin: 10px 0 !important;
2939 margin: 10px 0 !important;
2936 position: relative;
2940 position: relative;
2937 vertical-align: top;
2941 vertical-align: top;
2938 padding: 10px;
2942 padding: 10px;
2939 border-bottom: 1px solid @grey5;
2943 border-bottom: 1px solid @grey5;
2940 }
2944 }
2941
2945
2942 .dz-filename {
2946 .dz-filename {
2943 font-weight: 700;
2947 font-weight: 700;
2944 float: left;
2948 float: left;
2945 }
2949 }
2946
2950
2947 .dz-sending {
2951 .dz-sending {
2948 float: right;
2952 float: right;
2949 }
2953 }
2950
2954
2951 .dz-response {
2955 .dz-response {
2952 clear: both
2956 clear: both
2953 }
2957 }
2954
2958
2955 .dz-filename-size {
2959 .dz-filename-size {
2956 float: right
2960 float: right
2957 }
2961 }
2958
2962
2959 .dz-error-message {
2963 .dz-error-message {
2960 color: @alert2;
2964 color: @alert2;
2961 padding-top: 10px;
2965 padding-top: 10px;
2962 clear: both;
2966 clear: both;
2963 }
2967 }
2964
2968
2965
2969
2966 .user-hovercard {
2970 .user-hovercard {
2967 padding: 5px;
2971 padding: 5px;
2968 }
2972 }
2969
2973
2970 .user-hovercard-icon {
2974 .user-hovercard-icon {
2971 display: inline;
2975 display: inline;
2972 padding: 0;
2976 padding: 0;
2973 box-sizing: content-box;
2977 box-sizing: content-box;
2974 border-radius: 50%;
2978 border-radius: 50%;
2975 float: left;
2979 float: left;
2976 }
2980 }
2977
2981
2978 .user-hovercard-name {
2982 .user-hovercard-name {
2979 float: right;
2983 float: right;
2980 vertical-align: top;
2984 vertical-align: top;
2981 padding-left: 10px;
2985 padding-left: 10px;
2982 min-width: 150px;
2986 min-width: 150px;
2983 }
2987 }
2984
2988
2985 .user-hovercard-bio {
2989 .user-hovercard-bio {
2986 clear: both;
2990 clear: both;
2987 padding-top: 10px;
2991 padding-top: 10px;
2988 }
2992 }
2989
2993
2990 .user-hovercard-header {
2994 .user-hovercard-header {
2991 clear: both;
2995 clear: both;
2992 min-height: 10px;
2996 min-height: 10px;
2993 }
2997 }
2994
2998
2995 .user-hovercard-footer {
2999 .user-hovercard-footer {
2996 clear: both;
3000 clear: both;
2997 min-height: 10px;
3001 min-height: 10px;
2998 }
3002 }
2999
3003
3000 .user-group-hovercard {
3004 .user-group-hovercard {
3001 padding: 5px;
3005 padding: 5px;
3002 }
3006 }
3003
3007
3004 .user-group-hovercard-icon {
3008 .user-group-hovercard-icon {
3005 display: inline;
3009 display: inline;
3006 padding: 0;
3010 padding: 0;
3007 box-sizing: content-box;
3011 box-sizing: content-box;
3008 border-radius: 50%;
3012 border-radius: 50%;
3009 float: left;
3013 float: left;
3010 }
3014 }
3011
3015
3012 .user-group-hovercard-name {
3016 .user-group-hovercard-name {
3013 float: left;
3017 float: left;
3014 vertical-align: top;
3018 vertical-align: top;
3015 padding-left: 10px;
3019 padding-left: 10px;
3016 min-width: 150px;
3020 min-width: 150px;
3017 }
3021 }
3018
3022
3019 .user-group-hovercard-icon i {
3023 .user-group-hovercard-icon i {
3020 border: 1px solid @grey4;
3024 border: 1px solid @grey4;
3021 border-radius: 4px;
3025 border-radius: 4px;
3022 }
3026 }
3023
3027
3024 .user-group-hovercard-bio {
3028 .user-group-hovercard-bio {
3025 clear: both;
3029 clear: both;
3026 padding-top: 10px;
3030 padding-top: 10px;
3027 line-height: 1.0em;
3031 line-height: 1.0em;
3028 }
3032 }
3029
3033
3030 .user-group-hovercard-header {
3034 .user-group-hovercard-header {
3031 clear: both;
3035 clear: both;
3032 min-height: 10px;
3036 min-height: 10px;
3033 }
3037 }
3034
3038
3035 .user-group-hovercard-footer {
3039 .user-group-hovercard-footer {
3036 clear: both;
3040 clear: both;
3037 min-height: 10px;
3041 min-height: 10px;
3038 }
3042 }
3039
3043
3040 .pr-hovercard-header {
3044 .pr-hovercard-header {
3041 clear: both;
3045 clear: both;
3042 display: block;
3046 display: block;
3043 line-height: 20px;
3047 line-height: 20px;
3044 }
3048 }
3045
3049
3046 .pr-hovercard-user {
3050 .pr-hovercard-user {
3047 display: flex;
3051 display: flex;
3048 align-items: center;
3052 align-items: center;
3049 padding-left: 5px;
3053 padding-left: 5px;
3050 }
3054 }
3051
3055
3052 .pr-hovercard-title {
3056 .pr-hovercard-title {
3053 padding-top: 5px;
3057 padding-top: 5px;
3054 } No newline at end of file
3058 }
@@ -1,394 +1,395 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('favicon', '/favicon.ico', []);
15 pyroutes.register('favicon', '/favicon.ico', []);
16 pyroutes.register('robots', '/robots.txt', []);
16 pyroutes.register('robots', '/robots.txt', []);
17 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
17 pyroutes.register('auth_home', '/_admin/auth*traverse', []);
18 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
18 pyroutes.register('global_integrations_new', '/_admin/integrations/new', []);
19 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
19 pyroutes.register('global_integrations_home', '/_admin/integrations', []);
20 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
20 pyroutes.register('global_integrations_list', '/_admin/integrations/%(integration)s', ['integration']);
21 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
21 pyroutes.register('global_integrations_create', '/_admin/integrations/%(integration)s/new', ['integration']);
22 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
22 pyroutes.register('global_integrations_edit', '/_admin/integrations/%(integration)s/%(integration_id)s', ['integration', 'integration_id']);
23 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
23 pyroutes.register('repo_group_integrations_home', '/%(repo_group_name)s/_settings/integrations', ['repo_group_name']);
24 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
24 pyroutes.register('repo_group_integrations_new', '/%(repo_group_name)s/_settings/integrations/new', ['repo_group_name']);
25 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
25 pyroutes.register('repo_group_integrations_list', '/%(repo_group_name)s/_settings/integrations/%(integration)s', ['repo_group_name', 'integration']);
26 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
26 pyroutes.register('repo_group_integrations_create', '/%(repo_group_name)s/_settings/integrations/%(integration)s/new', ['repo_group_name', 'integration']);
27 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
27 pyroutes.register('repo_group_integrations_edit', '/%(repo_group_name)s/_settings/integrations/%(integration)s/%(integration_id)s', ['repo_group_name', 'integration', 'integration_id']);
28 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
28 pyroutes.register('repo_integrations_home', '/%(repo_name)s/settings/integrations', ['repo_name']);
29 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
29 pyroutes.register('repo_integrations_new', '/%(repo_name)s/settings/integrations/new', ['repo_name']);
30 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
30 pyroutes.register('repo_integrations_list', '/%(repo_name)s/settings/integrations/%(integration)s', ['repo_name', 'integration']);
31 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
31 pyroutes.register('repo_integrations_create', '/%(repo_name)s/settings/integrations/%(integration)s/new', ['repo_name', 'integration']);
32 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
32 pyroutes.register('repo_integrations_edit', '/%(repo_name)s/settings/integrations/%(integration)s/%(integration_id)s', ['repo_name', 'integration', 'integration_id']);
33 pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
33 pyroutes.register('hovercard_user', '/_hovercard/user/%(user_id)s', ['user_id']);
34 pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']);
34 pyroutes.register('hovercard_username', '/_hovercard/username/%(username)s', ['username']);
35 pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
35 pyroutes.register('hovercard_user_group', '/_hovercard/user_group/%(user_group_id)s', ['user_group_id']);
36 pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
36 pyroutes.register('hovercard_pull_request', '/_hovercard/pull_request/%(pull_request_id)s', ['pull_request_id']);
37 pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
37 pyroutes.register('hovercard_repo_commit', '/_hovercard/commit/%(repo_name)s/%(commit_id)s', ['repo_name', 'commit_id']);
38 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
38 pyroutes.register('ops_ping', '/_admin/ops/ping', []);
39 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
39 pyroutes.register('ops_error_test', '/_admin/ops/error', []);
40 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
40 pyroutes.register('ops_redirect_test', '/_admin/ops/redirect', []);
41 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
41 pyroutes.register('ops_ping_legacy', '/_admin/ping', []);
42 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
42 pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []);
43 pyroutes.register('admin_home', '/_admin', []);
43 pyroutes.register('admin_home', '/_admin', []);
44 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
44 pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []);
45 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
45 pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']);
46 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
46 pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']);
47 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
47 pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']);
48 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
48 pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']);
49 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
49 pyroutes.register('admin_settings_open_source', '/_admin/settings/open_source', []);
50 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
50 pyroutes.register('admin_settings_vcs_svn_generate_cfg', '/_admin/settings/vcs/svn_generate_cfg', []);
51 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
51 pyroutes.register('admin_settings_system', '/_admin/settings/system', []);
52 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
52 pyroutes.register('admin_settings_system_update', '/_admin/settings/system/updates', []);
53 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
53 pyroutes.register('admin_settings_exception_tracker', '/_admin/settings/exceptions', []);
54 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
54 pyroutes.register('admin_settings_exception_tracker_delete_all', '/_admin/settings/exceptions/delete', []);
55 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
55 pyroutes.register('admin_settings_exception_tracker_show', '/_admin/settings/exceptions/%(exception_id)s', ['exception_id']);
56 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
56 pyroutes.register('admin_settings_exception_tracker_delete', '/_admin/settings/exceptions/%(exception_id)s/delete', ['exception_id']);
57 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
57 pyroutes.register('admin_settings_sessions', '/_admin/settings/sessions', []);
58 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
58 pyroutes.register('admin_settings_sessions_cleanup', '/_admin/settings/sessions/cleanup', []);
59 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
59 pyroutes.register('admin_settings_process_management', '/_admin/settings/process_management', []);
60 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
60 pyroutes.register('admin_settings_process_management_data', '/_admin/settings/process_management/data', []);
61 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
61 pyroutes.register('admin_settings_process_management_signal', '/_admin/settings/process_management/signal', []);
62 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
62 pyroutes.register('admin_settings_process_management_master_signal', '/_admin/settings/process_management/master_signal', []);
63 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
63 pyroutes.register('admin_defaults_repositories', '/_admin/defaults/repositories', []);
64 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
64 pyroutes.register('admin_defaults_repositories_update', '/_admin/defaults/repositories/update', []);
65 pyroutes.register('admin_settings', '/_admin/settings', []);
65 pyroutes.register('admin_settings', '/_admin/settings', []);
66 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
66 pyroutes.register('admin_settings_update', '/_admin/settings/update', []);
67 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
67 pyroutes.register('admin_settings_global', '/_admin/settings/global', []);
68 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
68 pyroutes.register('admin_settings_global_update', '/_admin/settings/global/update', []);
69 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
69 pyroutes.register('admin_settings_vcs', '/_admin/settings/vcs', []);
70 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
70 pyroutes.register('admin_settings_vcs_update', '/_admin/settings/vcs/update', []);
71 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
71 pyroutes.register('admin_settings_vcs_svn_pattern_delete', '/_admin/settings/vcs/svn_pattern_delete', []);
72 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
72 pyroutes.register('admin_settings_mapping', '/_admin/settings/mapping', []);
73 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
73 pyroutes.register('admin_settings_mapping_update', '/_admin/settings/mapping/update', []);
74 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
74 pyroutes.register('admin_settings_visual', '/_admin/settings/visual', []);
75 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
75 pyroutes.register('admin_settings_visual_update', '/_admin/settings/visual/update', []);
76 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
76 pyroutes.register('admin_settings_issuetracker', '/_admin/settings/issue-tracker', []);
77 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
77 pyroutes.register('admin_settings_issuetracker_update', '/_admin/settings/issue-tracker/update', []);
78 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
78 pyroutes.register('admin_settings_issuetracker_test', '/_admin/settings/issue-tracker/test', []);
79 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
79 pyroutes.register('admin_settings_issuetracker_delete', '/_admin/settings/issue-tracker/delete', []);
80 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
80 pyroutes.register('admin_settings_email', '/_admin/settings/email', []);
81 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
81 pyroutes.register('admin_settings_email_update', '/_admin/settings/email/update', []);
82 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
82 pyroutes.register('admin_settings_hooks', '/_admin/settings/hooks', []);
83 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
83 pyroutes.register('admin_settings_hooks_update', '/_admin/settings/hooks/update', []);
84 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
84 pyroutes.register('admin_settings_hooks_delete', '/_admin/settings/hooks/delete', []);
85 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
85 pyroutes.register('admin_settings_search', '/_admin/settings/search', []);
86 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
86 pyroutes.register('admin_settings_labs', '/_admin/settings/labs', []);
87 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
87 pyroutes.register('admin_settings_labs_update', '/_admin/settings/labs/update', []);
88 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
88 pyroutes.register('admin_permissions_application', '/_admin/permissions/application', []);
89 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
89 pyroutes.register('admin_permissions_application_update', '/_admin/permissions/application/update', []);
90 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
90 pyroutes.register('admin_permissions_global', '/_admin/permissions/global', []);
91 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
91 pyroutes.register('admin_permissions_global_update', '/_admin/permissions/global/update', []);
92 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
92 pyroutes.register('admin_permissions_object', '/_admin/permissions/object', []);
93 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
93 pyroutes.register('admin_permissions_object_update', '/_admin/permissions/object/update', []);
94 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
94 pyroutes.register('admin_permissions_ips', '/_admin/permissions/ips', []);
95 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
95 pyroutes.register('admin_permissions_overview', '/_admin/permissions/overview', []);
96 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
96 pyroutes.register('admin_permissions_auth_token_access', '/_admin/permissions/auth_token_access', []);
97 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
97 pyroutes.register('admin_permissions_ssh_keys', '/_admin/permissions/ssh_keys', []);
98 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
98 pyroutes.register('admin_permissions_ssh_keys_data', '/_admin/permissions/ssh_keys/data', []);
99 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
99 pyroutes.register('admin_permissions_ssh_keys_update', '/_admin/permissions/ssh_keys/update', []);
100 pyroutes.register('users', '/_admin/users', []);
100 pyroutes.register('users', '/_admin/users', []);
101 pyroutes.register('users_data', '/_admin/users_data', []);
101 pyroutes.register('users_data', '/_admin/users_data', []);
102 pyroutes.register('users_create', '/_admin/users/create', []);
102 pyroutes.register('users_create', '/_admin/users/create', []);
103 pyroutes.register('users_new', '/_admin/users/new', []);
103 pyroutes.register('users_new', '/_admin/users/new', []);
104 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
104 pyroutes.register('user_edit', '/_admin/users/%(user_id)s/edit', ['user_id']);
105 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
105 pyroutes.register('user_edit_advanced', '/_admin/users/%(user_id)s/edit/advanced', ['user_id']);
106 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
106 pyroutes.register('user_edit_global_perms', '/_admin/users/%(user_id)s/edit/global_permissions', ['user_id']);
107 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
107 pyroutes.register('user_edit_global_perms_update', '/_admin/users/%(user_id)s/edit/global_permissions/update', ['user_id']);
108 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
108 pyroutes.register('user_update', '/_admin/users/%(user_id)s/update', ['user_id']);
109 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
109 pyroutes.register('user_delete', '/_admin/users/%(user_id)s/delete', ['user_id']);
110 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
110 pyroutes.register('user_enable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_enable', ['user_id']);
111 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
111 pyroutes.register('user_disable_force_password_reset', '/_admin/users/%(user_id)s/password_reset_disable', ['user_id']);
112 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
112 pyroutes.register('user_create_personal_repo_group', '/_admin/users/%(user_id)s/create_repo_group', ['user_id']);
113 pyroutes.register('user_notice_dismiss', '/_admin/users/%(user_id)s/notice_dismiss', ['user_id']);
113 pyroutes.register('user_notice_dismiss', '/_admin/users/%(user_id)s/notice_dismiss', ['user_id']);
114 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
114 pyroutes.register('edit_user_auth_tokens_delete', '/_admin/users/%(user_id)s/edit/auth_tokens/delete', ['user_id']);
115 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
115 pyroutes.register('edit_user_ssh_keys', '/_admin/users/%(user_id)s/edit/ssh_keys', ['user_id']);
116 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
116 pyroutes.register('edit_user_ssh_keys_generate_keypair', '/_admin/users/%(user_id)s/edit/ssh_keys/generate', ['user_id']);
117 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
117 pyroutes.register('edit_user_ssh_keys_add', '/_admin/users/%(user_id)s/edit/ssh_keys/new', ['user_id']);
118 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
118 pyroutes.register('edit_user_ssh_keys_delete', '/_admin/users/%(user_id)s/edit/ssh_keys/delete', ['user_id']);
119 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
119 pyroutes.register('edit_user_emails', '/_admin/users/%(user_id)s/edit/emails', ['user_id']);
120 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
120 pyroutes.register('edit_user_emails_add', '/_admin/users/%(user_id)s/edit/emails/new', ['user_id']);
121 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
121 pyroutes.register('edit_user_emails_delete', '/_admin/users/%(user_id)s/edit/emails/delete', ['user_id']);
122 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
122 pyroutes.register('edit_user_ips', '/_admin/users/%(user_id)s/edit/ips', ['user_id']);
123 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
123 pyroutes.register('edit_user_ips_add', '/_admin/users/%(user_id)s/edit/ips/new', ['user_id']);
124 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
124 pyroutes.register('edit_user_ips_delete', '/_admin/users/%(user_id)s/edit/ips/delete', ['user_id']);
125 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
125 pyroutes.register('edit_user_perms_summary', '/_admin/users/%(user_id)s/edit/permissions_summary', ['user_id']);
126 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
126 pyroutes.register('edit_user_perms_summary_json', '/_admin/users/%(user_id)s/edit/permissions_summary/json', ['user_id']);
127 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
127 pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']);
128 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
128 pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']);
129 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
129 pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']);
130 pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']);
130 pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']);
131 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
131 pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']);
132 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
132 pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']);
133 pyroutes.register('user_groups', '/_admin/user_groups', []);
133 pyroutes.register('user_groups', '/_admin/user_groups', []);
134 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
134 pyroutes.register('user_groups_data', '/_admin/user_groups_data', []);
135 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
135 pyroutes.register('user_groups_new', '/_admin/user_groups/new', []);
136 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
136 pyroutes.register('user_groups_create', '/_admin/user_groups/create', []);
137 pyroutes.register('repos', '/_admin/repos', []);
137 pyroutes.register('repos', '/_admin/repos', []);
138 pyroutes.register('repos_data', '/_admin/repos_data', []);
138 pyroutes.register('repos_data', '/_admin/repos_data', []);
139 pyroutes.register('repo_new', '/_admin/repos/new', []);
139 pyroutes.register('repo_new', '/_admin/repos/new', []);
140 pyroutes.register('repo_create', '/_admin/repos/create', []);
140 pyroutes.register('repo_create', '/_admin/repos/create', []);
141 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
141 pyroutes.register('repo_groups', '/_admin/repo_groups', []);
142 pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []);
142 pyroutes.register('repo_groups_data', '/_admin/repo_groups_data', []);
143 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
143 pyroutes.register('repo_group_new', '/_admin/repo_group/new', []);
144 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
144 pyroutes.register('repo_group_create', '/_admin/repo_group/create', []);
145 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
145 pyroutes.register('channelstream_connect', '/_admin/channelstream/connect', []);
146 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
146 pyroutes.register('channelstream_subscribe', '/_admin/channelstream/subscribe', []);
147 pyroutes.register('channelstream_proxy', '/_channelstream', []);
147 pyroutes.register('channelstream_proxy', '/_channelstream', []);
148 pyroutes.register('upload_file', '/_file_store/upload', []);
148 pyroutes.register('upload_file', '/_file_store/upload', []);
149 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
149 pyroutes.register('download_file', '/_file_store/download/%(fid)s', ['fid']);
150 pyroutes.register('download_file_by_token', '/_file_store/token-download/%(_auth_token)s/%(fid)s', ['_auth_token', 'fid']);
150 pyroutes.register('download_file_by_token', '/_file_store/token-download/%(_auth_token)s/%(fid)s', ['_auth_token', 'fid']);
151 pyroutes.register('logout', '/_admin/logout', []);
151 pyroutes.register('logout', '/_admin/logout', []);
152 pyroutes.register('reset_password', '/_admin/password_reset', []);
152 pyroutes.register('reset_password', '/_admin/password_reset', []);
153 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
153 pyroutes.register('reset_password_confirmation', '/_admin/password_reset_confirmation', []);
154 pyroutes.register('home', '/', []);
154 pyroutes.register('home', '/', []);
155 pyroutes.register('main_page_repos_data', '/_home_repos', []);
155 pyroutes.register('main_page_repos_data', '/_home_repos', []);
156 pyroutes.register('main_page_repo_groups_data', '/_home_repo_groups', []);
156 pyroutes.register('main_page_repo_groups_data', '/_home_repo_groups', []);
157 pyroutes.register('user_autocomplete_data', '/_users', []);
157 pyroutes.register('user_autocomplete_data', '/_users', []);
158 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
158 pyroutes.register('user_group_autocomplete_data', '/_user_groups', []);
159 pyroutes.register('repo_list_data', '/_repos', []);
159 pyroutes.register('repo_list_data', '/_repos', []);
160 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
160 pyroutes.register('repo_group_list_data', '/_repo_groups', []);
161 pyroutes.register('goto_switcher_data', '/_goto_data', []);
161 pyroutes.register('goto_switcher_data', '/_goto_data', []);
162 pyroutes.register('markup_preview', '/_markup_preview', []);
162 pyroutes.register('markup_preview', '/_markup_preview', []);
163 pyroutes.register('file_preview', '/_file_preview', []);
163 pyroutes.register('file_preview', '/_file_preview', []);
164 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
164 pyroutes.register('store_user_session_value', '/_store_session_attr', []);
165 pyroutes.register('journal', '/_admin/journal', []);
165 pyroutes.register('journal', '/_admin/journal', []);
166 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
166 pyroutes.register('journal_rss', '/_admin/journal/rss', []);
167 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
167 pyroutes.register('journal_atom', '/_admin/journal/atom', []);
168 pyroutes.register('journal_public', '/_admin/public_journal', []);
168 pyroutes.register('journal_public', '/_admin/public_journal', []);
169 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
169 pyroutes.register('journal_public_atom', '/_admin/public_journal/atom', []);
170 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
170 pyroutes.register('journal_public_atom_old', '/_admin/public_journal_atom', []);
171 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
171 pyroutes.register('journal_public_rss', '/_admin/public_journal/rss', []);
172 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
172 pyroutes.register('journal_public_rss_old', '/_admin/public_journal_rss', []);
173 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
173 pyroutes.register('toggle_following', '/_admin/toggle_following', []);
174 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
174 pyroutes.register('repo_creating', '/%(repo_name)s/repo_creating', ['repo_name']);
175 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
175 pyroutes.register('repo_creating_check', '/%(repo_name)s/repo_creating_check', ['repo_name']);
176 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
176 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
177 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
177 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
178 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
178 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
179 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
179 pyroutes.register('repo_commit_children', '/%(repo_name)s/changeset_children/%(commit_id)s', ['repo_name', 'commit_id']);
180 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
180 pyroutes.register('repo_commit_parents', '/%(repo_name)s/changeset_parents/%(commit_id)s', ['repo_name', 'commit_id']);
181 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
181 pyroutes.register('repo_commit_raw', '/%(repo_name)s/changeset-diff/%(commit_id)s', ['repo_name', 'commit_id']);
182 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
182 pyroutes.register('repo_commit_patch', '/%(repo_name)s/changeset-patch/%(commit_id)s', ['repo_name', 'commit_id']);
183 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
183 pyroutes.register('repo_commit_download', '/%(repo_name)s/changeset-download/%(commit_id)s', ['repo_name', 'commit_id']);
184 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
184 pyroutes.register('repo_commit_data', '/%(repo_name)s/changeset-data/%(commit_id)s', ['repo_name', 'commit_id']);
185 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
185 pyroutes.register('repo_commit_comment_create', '/%(repo_name)s/changeset/%(commit_id)s/comment/create', ['repo_name', 'commit_id']);
186 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
186 pyroutes.register('repo_commit_comment_preview', '/%(repo_name)s/changeset/%(commit_id)s/comment/preview', ['repo_name', 'commit_id']);
187 pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']);
187 pyroutes.register('repo_commit_comment_attachment_upload', '/%(repo_name)s/changeset/%(commit_id)s/comment/attachment_upload', ['repo_name', 'commit_id']);
188 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
188 pyroutes.register('repo_commit_comment_delete', '/%(repo_name)s/changeset/%(commit_id)s/comment/%(comment_id)s/delete', ['repo_name', 'commit_id', 'comment_id']);
189 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
189 pyroutes.register('repo_commit_raw_deprecated', '/%(repo_name)s/raw-changeset/%(commit_id)s', ['repo_name', 'commit_id']);
190 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
190 pyroutes.register('repo_archivefile', '/%(repo_name)s/archive/%(fname)s', ['repo_name', 'fname']);
191 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
191 pyroutes.register('repo_files_diff', '/%(repo_name)s/diff/%(f_path)s', ['repo_name', 'f_path']);
192 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
192 pyroutes.register('repo_files_diff_2way_redirect', '/%(repo_name)s/diff-2way/%(f_path)s', ['repo_name', 'f_path']);
193 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
193 pyroutes.register('repo_files', '/%(repo_name)s/files/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
194 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
194 pyroutes.register('repo_files:default_path', '/%(repo_name)s/files/%(commit_id)s/', ['repo_name', 'commit_id']);
195 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
195 pyroutes.register('repo_files:default_commit', '/%(repo_name)s/files', ['repo_name']);
196 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
196 pyroutes.register('repo_files:rendered', '/%(repo_name)s/render/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
197 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
197 pyroutes.register('repo_files:annotated', '/%(repo_name)s/annotate/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
198 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
198 pyroutes.register('repo_files:annotated_previous', '/%(repo_name)s/annotate-previous/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
199 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
199 pyroutes.register('repo_nodetree_full', '/%(repo_name)s/nodetree_full/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
200 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
200 pyroutes.register('repo_nodetree_full:default_path', '/%(repo_name)s/nodetree_full/%(commit_id)s/', ['repo_name', 'commit_id']);
201 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
201 pyroutes.register('repo_files_nodelist', '/%(repo_name)s/nodelist/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
202 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
202 pyroutes.register('repo_file_raw', '/%(repo_name)s/raw/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
203 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
203 pyroutes.register('repo_file_download', '/%(repo_name)s/download/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
204 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
204 pyroutes.register('repo_file_download:legacy', '/%(repo_name)s/rawfile/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
205 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
205 pyroutes.register('repo_file_history', '/%(repo_name)s/history/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
206 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
206 pyroutes.register('repo_file_authors', '/%(repo_name)s/authors/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
207 pyroutes.register('repo_files_check_head', '/%(repo_name)s/check_head/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
207 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
208 pyroutes.register('repo_files_remove_file', '/%(repo_name)s/remove_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
208 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
209 pyroutes.register('repo_files_delete_file', '/%(repo_name)s/delete_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
209 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
210 pyroutes.register('repo_files_edit_file', '/%(repo_name)s/edit_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
210 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
211 pyroutes.register('repo_files_update_file', '/%(repo_name)s/update_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
211 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
212 pyroutes.register('repo_files_add_file', '/%(repo_name)s/add_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
212 pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
213 pyroutes.register('repo_files_upload_file', '/%(repo_name)s/upload_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
213 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
214 pyroutes.register('repo_files_create_file', '/%(repo_name)s/create_file/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
214 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
215 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
215 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
216 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
216 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
217 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
217 pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']);
218 pyroutes.register('repo_commits', '/%(repo_name)s/commits', ['repo_name']);
218 pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
219 pyroutes.register('repo_commits_file', '/%(repo_name)s/commits/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
219 pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']);
220 pyroutes.register('repo_commits_elements', '/%(repo_name)s/commits_elements', ['repo_name']);
220 pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
221 pyroutes.register('repo_commits_elements_file', '/%(repo_name)s/commits_elements/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
221 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
222 pyroutes.register('repo_changelog', '/%(repo_name)s/changelog', ['repo_name']);
222 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
223 pyroutes.register('repo_changelog_file', '/%(repo_name)s/changelog/%(commit_id)s/%(f_path)s', ['repo_name', 'commit_id', 'f_path']);
223 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
224 pyroutes.register('repo_compare_select', '/%(repo_name)s/compare', ['repo_name']);
224 pyroutes.register('repo_compare', '/%(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']);
225 pyroutes.register('repo_compare', '/%(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']);
225 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
226 pyroutes.register('tags_home', '/%(repo_name)s/tags', ['repo_name']);
226 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
227 pyroutes.register('branches_home', '/%(repo_name)s/branches', ['repo_name']);
227 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
228 pyroutes.register('bookmarks_home', '/%(repo_name)s/bookmarks', ['repo_name']);
228 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
229 pyroutes.register('repo_fork_new', '/%(repo_name)s/fork', ['repo_name']);
229 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
230 pyroutes.register('repo_fork_create', '/%(repo_name)s/fork/create', ['repo_name']);
230 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
231 pyroutes.register('repo_forks_show_all', '/%(repo_name)s/forks', ['repo_name']);
231 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
232 pyroutes.register('repo_forks_data', '/%(repo_name)s/forks/data', ['repo_name']);
232 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
233 pyroutes.register('pullrequest_show', '/%(repo_name)s/pull-request/%(pull_request_id)s', ['repo_name', 'pull_request_id']);
233 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
234 pyroutes.register('pullrequest_show_all', '/%(repo_name)s/pull-request', ['repo_name']);
234 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
235 pyroutes.register('pullrequest_show_all_data', '/%(repo_name)s/pull-request-data', ['repo_name']);
235 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
236 pyroutes.register('pullrequest_repo_refs', '/%(repo_name)s/pull-request/refs/%(target_repo_name)s', ['repo_name', 'target_repo_name']);
236 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
237 pyroutes.register('pullrequest_repo_targets', '/%(repo_name)s/pull-request/repo-targets', ['repo_name']);
237 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
238 pyroutes.register('pullrequest_new', '/%(repo_name)s/pull-request/new', ['repo_name']);
238 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
239 pyroutes.register('pullrequest_create', '/%(repo_name)s/pull-request/create', ['repo_name']);
239 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
240 pyroutes.register('pullrequest_update', '/%(repo_name)s/pull-request/%(pull_request_id)s/update', ['repo_name', 'pull_request_id']);
240 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
241 pyroutes.register('pullrequest_merge', '/%(repo_name)s/pull-request/%(pull_request_id)s/merge', ['repo_name', 'pull_request_id']);
241 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
242 pyroutes.register('pullrequest_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/delete', ['repo_name', 'pull_request_id']);
242 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
243 pyroutes.register('pullrequest_comment_create', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment', ['repo_name', 'pull_request_id']);
243 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
244 pyroutes.register('pullrequest_comment_delete', '/%(repo_name)s/pull-request/%(pull_request_id)s/comment/%(comment_id)s/delete', ['repo_name', 'pull_request_id', 'comment_id']);
244 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
245 pyroutes.register('edit_repo', '/%(repo_name)s/settings', ['repo_name']);
245 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
246 pyroutes.register('edit_repo_advanced', '/%(repo_name)s/settings/advanced', ['repo_name']);
246 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
247 pyroutes.register('edit_repo_advanced_archive', '/%(repo_name)s/settings/advanced/archive', ['repo_name']);
247 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
248 pyroutes.register('edit_repo_advanced_delete', '/%(repo_name)s/settings/advanced/delete', ['repo_name']);
248 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
249 pyroutes.register('edit_repo_advanced_locking', '/%(repo_name)s/settings/advanced/locking', ['repo_name']);
249 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
250 pyroutes.register('edit_repo_advanced_journal', '/%(repo_name)s/settings/advanced/journal', ['repo_name']);
250 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
251 pyroutes.register('edit_repo_advanced_fork', '/%(repo_name)s/settings/advanced/fork', ['repo_name']);
251 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
252 pyroutes.register('edit_repo_advanced_hooks', '/%(repo_name)s/settings/advanced/hooks', ['repo_name']);
252 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
253 pyroutes.register('edit_repo_caches', '/%(repo_name)s/settings/caches', ['repo_name']);
253 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
254 pyroutes.register('edit_repo_perms', '/%(repo_name)s/settings/permissions', ['repo_name']);
254 pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']);
255 pyroutes.register('edit_repo_perms_set_private', '/%(repo_name)s/settings/permissions/set_private', ['repo_name']);
255 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
256 pyroutes.register('edit_repo_maintenance', '/%(repo_name)s/settings/maintenance', ['repo_name']);
256 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
257 pyroutes.register('edit_repo_maintenance_execute', '/%(repo_name)s/settings/maintenance/execute', ['repo_name']);
257 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
258 pyroutes.register('edit_repo_fields', '/%(repo_name)s/settings/fields', ['repo_name']);
258 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
259 pyroutes.register('edit_repo_fields_create', '/%(repo_name)s/settings/fields/create', ['repo_name']);
259 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
260 pyroutes.register('edit_repo_fields_delete', '/%(repo_name)s/settings/fields/%(field_id)s/delete', ['repo_name', 'field_id']);
260 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
261 pyroutes.register('repo_edit_toggle_locking', '/%(repo_name)s/settings/toggle_locking', ['repo_name']);
261 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
262 pyroutes.register('edit_repo_remote', '/%(repo_name)s/settings/remote', ['repo_name']);
262 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
263 pyroutes.register('edit_repo_remote_pull', '/%(repo_name)s/settings/remote/pull', ['repo_name']);
263 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
264 pyroutes.register('edit_repo_statistics', '/%(repo_name)s/settings/statistics', ['repo_name']);
264 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
265 pyroutes.register('edit_repo_statistics_reset', '/%(repo_name)s/settings/statistics/update', ['repo_name']);
265 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
266 pyroutes.register('edit_repo_issuetracker', '/%(repo_name)s/settings/issue_trackers', ['repo_name']);
266 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
267 pyroutes.register('edit_repo_issuetracker_test', '/%(repo_name)s/settings/issue_trackers/test', ['repo_name']);
267 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
268 pyroutes.register('edit_repo_issuetracker_delete', '/%(repo_name)s/settings/issue_trackers/delete', ['repo_name']);
268 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
269 pyroutes.register('edit_repo_issuetracker_update', '/%(repo_name)s/settings/issue_trackers/update', ['repo_name']);
269 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
270 pyroutes.register('edit_repo_vcs', '/%(repo_name)s/settings/vcs', ['repo_name']);
270 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
271 pyroutes.register('edit_repo_vcs_update', '/%(repo_name)s/settings/vcs/update', ['repo_name']);
271 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
272 pyroutes.register('edit_repo_vcs_svn_pattern_delete', '/%(repo_name)s/settings/vcs/svn_pattern/delete', ['repo_name']);
272 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
273 pyroutes.register('repo_reviewers', '/%(repo_name)s/settings/review/rules', ['repo_name']);
273 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
274 pyroutes.register('repo_default_reviewers_data', '/%(repo_name)s/settings/review/default-reviewers', ['repo_name']);
274 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
275 pyroutes.register('edit_repo_strip', '/%(repo_name)s/settings/strip', ['repo_name']);
275 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
276 pyroutes.register('strip_check', '/%(repo_name)s/settings/strip_check', ['repo_name']);
276 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
277 pyroutes.register('strip_execute', '/%(repo_name)s/settings/strip_execute', ['repo_name']);
277 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
278 pyroutes.register('edit_repo_audit_logs', '/%(repo_name)s/settings/audit_logs', ['repo_name']);
278 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']);
279 pyroutes.register('rss_feed_home', '/%(repo_name)s/feed-rss', ['repo_name']);
279 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
280 pyroutes.register('atom_feed_home', '/%(repo_name)s/feed-atom', ['repo_name']);
280 pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']);
281 pyroutes.register('rss_feed_home_old', '/%(repo_name)s/feed/rss', ['repo_name']);
281 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
282 pyroutes.register('atom_feed_home_old', '/%(repo_name)s/feed/atom', ['repo_name']);
282 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
283 pyroutes.register('repo_summary', '/%(repo_name)s', ['repo_name']);
283 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
284 pyroutes.register('repo_summary_slash', '/%(repo_name)s/', ['repo_name']);
284 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
285 pyroutes.register('edit_repo_group', '/%(repo_group_name)s/_edit', ['repo_group_name']);
285 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
286 pyroutes.register('edit_repo_group_advanced', '/%(repo_group_name)s/_settings/advanced', ['repo_group_name']);
286 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
287 pyroutes.register('edit_repo_group_advanced_delete', '/%(repo_group_name)s/_settings/advanced/delete', ['repo_group_name']);
287 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
288 pyroutes.register('edit_repo_group_perms', '/%(repo_group_name)s/_settings/permissions', ['repo_group_name']);
288 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
289 pyroutes.register('edit_repo_group_perms_update', '/%(repo_group_name)s/_settings/permissions/update', ['repo_group_name']);
289 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
290 pyroutes.register('repo_group_home', '/%(repo_group_name)s', ['repo_group_name']);
290 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
291 pyroutes.register('repo_group_home_slash', '/%(repo_group_name)s/', ['repo_group_name']);
291 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
292 pyroutes.register('user_group_members_data', '/_admin/user_groups/%(user_group_id)s/members', ['user_group_id']);
292 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
293 pyroutes.register('edit_user_group_perms_summary', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary', ['user_group_id']);
293 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
294 pyroutes.register('edit_user_group_perms_summary_json', '/_admin/user_groups/%(user_group_id)s/edit/permissions_summary/json', ['user_group_id']);
294 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
295 pyroutes.register('edit_user_group', '/_admin/user_groups/%(user_group_id)s/edit', ['user_group_id']);
295 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
296 pyroutes.register('user_groups_update', '/_admin/user_groups/%(user_group_id)s/update', ['user_group_id']);
296 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
297 pyroutes.register('edit_user_group_global_perms', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions', ['user_group_id']);
297 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
298 pyroutes.register('edit_user_group_global_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/global_permissions/update', ['user_group_id']);
298 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
299 pyroutes.register('edit_user_group_perms', '/_admin/user_groups/%(user_group_id)s/edit/permissions', ['user_group_id']);
299 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
300 pyroutes.register('edit_user_group_perms_update', '/_admin/user_groups/%(user_group_id)s/edit/permissions/update', ['user_group_id']);
300 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
301 pyroutes.register('edit_user_group_advanced', '/_admin/user_groups/%(user_group_id)s/edit/advanced', ['user_group_id']);
301 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
302 pyroutes.register('edit_user_group_advanced_sync', '/_admin/user_groups/%(user_group_id)s/edit/advanced/sync', ['user_group_id']);
302 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
303 pyroutes.register('user_groups_delete', '/_admin/user_groups/%(user_group_id)s/delete', ['user_group_id']);
303 pyroutes.register('search', '/_admin/search', []);
304 pyroutes.register('search', '/_admin/search', []);
304 pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']);
305 pyroutes.register('search_repo', '/%(repo_name)s/_search', ['repo_name']);
305 pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']);
306 pyroutes.register('search_repo_alt', '/%(repo_name)s/search', ['repo_name']);
306 pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']);
307 pyroutes.register('search_repo_group', '/%(repo_group_name)s/_search', ['repo_group_name']);
307 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
308 pyroutes.register('user_profile', '/_profiles/%(username)s', ['username']);
308 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
309 pyroutes.register('user_group_profile', '/_profile_user_group/%(user_group_name)s', ['user_group_name']);
309 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
310 pyroutes.register('my_account_profile', '/_admin/my_account/profile', []);
310 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
311 pyroutes.register('my_account_edit', '/_admin/my_account/edit', []);
311 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
312 pyroutes.register('my_account_update', '/_admin/my_account/update', []);
312 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
313 pyroutes.register('my_account_password', '/_admin/my_account/password', []);
313 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
314 pyroutes.register('my_account_password_update', '/_admin/my_account/password/update', []);
314 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
315 pyroutes.register('my_account_auth_tokens_delete', '/_admin/my_account/auth_tokens/delete', []);
315 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
316 pyroutes.register('my_account_ssh_keys', '/_admin/my_account/ssh_keys', []);
316 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
317 pyroutes.register('my_account_ssh_keys_generate', '/_admin/my_account/ssh_keys/generate', []);
317 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
318 pyroutes.register('my_account_ssh_keys_add', '/_admin/my_account/ssh_keys/new', []);
318 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
319 pyroutes.register('my_account_ssh_keys_delete', '/_admin/my_account/ssh_keys/delete', []);
319 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
320 pyroutes.register('my_account_user_group_membership', '/_admin/my_account/user_group_membership', []);
320 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
321 pyroutes.register('my_account_emails', '/_admin/my_account/emails', []);
321 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
322 pyroutes.register('my_account_emails_add', '/_admin/my_account/emails/new', []);
322 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
323 pyroutes.register('my_account_emails_delete', '/_admin/my_account/emails/delete', []);
323 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
324 pyroutes.register('my_account_repos', '/_admin/my_account/repos', []);
324 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
325 pyroutes.register('my_account_watched', '/_admin/my_account/watched', []);
325 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
326 pyroutes.register('my_account_bookmarks', '/_admin/my_account/bookmarks', []);
326 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
327 pyroutes.register('my_account_bookmarks_update', '/_admin/my_account/bookmarks/update', []);
327 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
328 pyroutes.register('my_account_goto_bookmark', '/_admin/my_account/bookmark/%(bookmark_id)s', ['bookmark_id']);
328 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
329 pyroutes.register('my_account_perms', '/_admin/my_account/perms', []);
329 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
330 pyroutes.register('my_account_notifications', '/_admin/my_account/notifications', []);
330 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
331 pyroutes.register('my_account_notifications_toggle_visibility', '/_admin/my_account/toggle_visibility', []);
331 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
332 pyroutes.register('my_account_pullrequests', '/_admin/my_account/pull_requests', []);
332 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
333 pyroutes.register('my_account_pullrequests_data', '/_admin/my_account/pull_requests/data', []);
333 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
334 pyroutes.register('notifications_show_all', '/_admin/notifications', []);
334 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
335 pyroutes.register('notifications_mark_all_read', '/_admin/notifications/mark_all_read', []);
335 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
336 pyroutes.register('notifications_show', '/_admin/notifications/%(notification_id)s', ['notification_id']);
336 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
337 pyroutes.register('notifications_update', '/_admin/notifications/%(notification_id)s/update', ['notification_id']);
337 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
338 pyroutes.register('notifications_delete', '/_admin/notifications/%(notification_id)s/delete', ['notification_id']);
338 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
339 pyroutes.register('my_account_notifications_test_channelstream', '/_admin/my_account/test_channelstream', []);
339 pyroutes.register('gists_show', '/_admin/gists', []);
340 pyroutes.register('gists_show', '/_admin/gists', []);
340 pyroutes.register('gists_new', '/_admin/gists/new', []);
341 pyroutes.register('gists_new', '/_admin/gists/new', []);
341 pyroutes.register('gists_create', '/_admin/gists/create', []);
342 pyroutes.register('gists_create', '/_admin/gists/create', []);
342 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
343 pyroutes.register('gist_show', '/_admin/gists/%(gist_id)s', ['gist_id']);
343 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
344 pyroutes.register('gist_delete', '/_admin/gists/%(gist_id)s/delete', ['gist_id']);
344 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
345 pyroutes.register('gist_edit', '/_admin/gists/%(gist_id)s/edit', ['gist_id']);
345 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
346 pyroutes.register('gist_edit_check_revision', '/_admin/gists/%(gist_id)s/edit/check_revision', ['gist_id']);
346 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
347 pyroutes.register('gist_update', '/_admin/gists/%(gist_id)s/update', ['gist_id']);
347 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
348 pyroutes.register('gist_show_rev', '/_admin/gists/%(gist_id)s/%(revision)s', ['gist_id', 'revision']);
348 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
349 pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
349 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
350 pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
350 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
351 pyroutes.register('debug_style_home', '/_admin/debug_style', []);
351 pyroutes.register('debug_style_email', '/_admin/debug_style/email/%(email_id)s', ['email_id']);
352 pyroutes.register('debug_style_email', '/_admin/debug_style/email/%(email_id)s', ['email_id']);
352 pyroutes.register('debug_style_email_plain_rendered', '/_admin/debug_style/email-rendered/%(email_id)s', ['email_id']);
353 pyroutes.register('debug_style_email_plain_rendered', '/_admin/debug_style/email-rendered/%(email_id)s', ['email_id']);
353 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
354 pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
354 pyroutes.register('apiv2', '/_admin/api', []);
355 pyroutes.register('apiv2', '/_admin/api', []);
355 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
356 pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
356 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
357 pyroutes.register('admin_settings_license_unlock', '/_admin/settings/license_unlock', []);
357 pyroutes.register('login', '/_admin/login', []);
358 pyroutes.register('login', '/_admin/login', []);
358 pyroutes.register('register', '/_admin/register', []);
359 pyroutes.register('register', '/_admin/register', []);
359 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
360 pyroutes.register('repo_reviewers_review_rule_new', '/%(repo_name)s/settings/review/rules/new', ['repo_name']);
360 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
361 pyroutes.register('repo_reviewers_review_rule_edit', '/%(repo_name)s/settings/review/rules/%(rule_id)s', ['repo_name', 'rule_id']);
361 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
362 pyroutes.register('repo_reviewers_review_rule_delete', '/%(repo_name)s/settings/review/rules/%(rule_id)s/delete', ['repo_name', 'rule_id']);
362 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
363 pyroutes.register('plugin_admin_chat', '/_admin/plugin_admin_chat/%(action)s', ['action']);
363 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
364 pyroutes.register('edit_user_auth_tokens', '/_admin/users/%(user_id)s/edit/auth_tokens', ['user_id']);
364 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
365 pyroutes.register('edit_user_auth_tokens_add', '/_admin/users/%(user_id)s/edit/auth_tokens/new', ['user_id']);
365 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
366 pyroutes.register('admin_settings_scheduler_show_tasks', '/_admin/settings/scheduler/_tasks', []);
366 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
367 pyroutes.register('admin_settings_scheduler_show_all', '/_admin/settings/scheduler', []);
367 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
368 pyroutes.register('admin_settings_scheduler_new', '/_admin/settings/scheduler/new', []);
368 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
369 pyroutes.register('admin_settings_scheduler_create', '/_admin/settings/scheduler/create', []);
369 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
370 pyroutes.register('admin_settings_scheduler_edit', '/_admin/settings/scheduler/%(schedule_id)s', ['schedule_id']);
370 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
371 pyroutes.register('admin_settings_scheduler_update', '/_admin/settings/scheduler/%(schedule_id)s/update', ['schedule_id']);
371 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
372 pyroutes.register('admin_settings_scheduler_delete', '/_admin/settings/scheduler/%(schedule_id)s/delete', ['schedule_id']);
372 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
373 pyroutes.register('admin_settings_scheduler_execute', '/_admin/settings/scheduler/%(schedule_id)s/execute', ['schedule_id']);
373 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
374 pyroutes.register('admin_settings_automation', '/_admin/settings/automation', []);
374 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
375 pyroutes.register('admin_settings_automation_update', '/_admin/settings/automation/%(entry_id)s/update', ['entry_id']);
375 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
376 pyroutes.register('admin_permissions_branch', '/_admin/permissions/branch', []);
376 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
377 pyroutes.register('admin_permissions_branch_update', '/_admin/permissions/branch/update', []);
377 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
378 pyroutes.register('my_account_auth_tokens', '/_admin/my_account/auth_tokens', []);
378 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
379 pyroutes.register('my_account_auth_tokens_add', '/_admin/my_account/auth_tokens/new', []);
379 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
380 pyroutes.register('my_account_external_identity', '/_admin/my_account/external-identity', []);
380 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
381 pyroutes.register('my_account_external_identity_delete', '/_admin/my_account/external-identity/delete', []);
381 pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']);
382 pyroutes.register('repo_artifacts_list', '/%(repo_name)s/artifacts', ['repo_name']);
382 pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']);
383 pyroutes.register('repo_artifacts_data', '/%(repo_name)s/artifacts_data', ['repo_name']);
383 pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']);
384 pyroutes.register('repo_artifacts_new', '/%(repo_name)s/artifacts/new', ['repo_name']);
384 pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']);
385 pyroutes.register('repo_artifacts_get', '/%(repo_name)s/artifacts/download/%(uid)s', ['repo_name', 'uid']);
385 pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']);
386 pyroutes.register('repo_artifacts_store', '/%(repo_name)s/artifacts/store', ['repo_name']);
386 pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']);
387 pyroutes.register('repo_artifacts_info', '/%(repo_name)s/artifacts/info/%(uid)s', ['repo_name', 'uid']);
387 pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']);
388 pyroutes.register('repo_artifacts_delete', '/%(repo_name)s/artifacts/delete/%(uid)s', ['repo_name', 'uid']);
388 pyroutes.register('repo_artifacts_update', '/%(repo_name)s/artifacts/update/%(uid)s', ['repo_name', 'uid']);
389 pyroutes.register('repo_artifacts_update', '/%(repo_name)s/artifacts/update/%(uid)s', ['repo_name', 'uid']);
389 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
390 pyroutes.register('repo_automation', '/%(repo_name)s/settings/automation', ['repo_name']);
390 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
391 pyroutes.register('repo_automation_update', '/%(repo_name)s/settings/automation/%(entry_id)s/update', ['repo_name', 'entry_id']);
391 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
392 pyroutes.register('edit_repo_remote_push', '/%(repo_name)s/settings/remote/push', ['repo_name']);
392 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
393 pyroutes.register('edit_repo_perms_branch', '/%(repo_name)s/settings/branch_permissions', ['repo_name']);
393 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
394 pyroutes.register('edit_repo_perms_branch_delete', '/%(repo_name)s/settings/branch_permissions/%(rule_id)s/delete', ['repo_name', 'rule_id']);
394 }
395 }
@@ -1,523 +1,600 b''
1 // # Copyright (C) 2010-2019 RhodeCode GmbH
1 // # Copyright (C) 2010-2019 RhodeCode GmbH
2 // #
2 // #
3 // # This program is free software: you can redistribute it and/or modify
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
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
5 // # (only), as published by the Free Software Foundation.
6 // #
6 // #
7 // # This program is distributed in the hope that it will be useful,
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
10 // # GNU General Public License for more details.
11 // #
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
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/>.
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 /**
19 /**
20 * Search file list
20 * Search file list
21 */
21 */
22
22
23 var NodeFilter = {};
23 var NodeFilter = {};
24
24
25 var fileBrowserListeners = function (node_list_url, url_base) {
25 var fileBrowserListeners = function (node_list_url, url_base) {
26 var $filterInput = $('#node_filter');
26 var $filterInput = $('#node_filter');
27 var n_filter = $filterInput.get(0);
27 var n_filter = $filterInput.get(0);
28
28
29 NodeFilter.filterTimeout = null;
29 NodeFilter.filterTimeout = null;
30 var nodes = null;
30 var nodes = null;
31
31
32 NodeFilter.focus = function () {
32 NodeFilter.focus = function () {
33 $filterInput.focus()
33 $filterInput.focus()
34 };
34 };
35
35
36 NodeFilter.fetchNodes = function (callback) {
36 NodeFilter.fetchNodes = function (callback) {
37 $.ajax(
37 $.ajax(
38 {url: node_list_url, headers: {'X-PARTIAL-XHR': true}})
38 {url: node_list_url, headers: {'X-PARTIAL-XHR': true}})
39 .done(function (data) {
39 .done(function (data) {
40 nodes = data.nodes;
40 nodes = data.nodes;
41 if (callback) {
41 if (callback) {
42 callback();
42 callback();
43 }
43 }
44 })
44 })
45 .fail(function (data) {
45 .fail(function (data) {
46 console.log('failed to load');
46 console.log('failed to load');
47 });
47 });
48 };
48 };
49
49
50 NodeFilter.initFilter = function (e) {
50 NodeFilter.initFilter = function (e) {
51 if ($filterInput.hasClass('loading')) {
51 if ($filterInput.hasClass('loading')) {
52 return
52 return
53 }
53 }
54
54
55 // in case we are already loaded, do nothing
55 // in case we are already loaded, do nothing
56 if (!$filterInput.hasClass('init')) {
56 if (!$filterInput.hasClass('init')) {
57 return NodeFilter.handleKey(e);
57 return NodeFilter.handleKey(e);
58 }
58 }
59 var iconLoading = 'icon-spin animate-spin';
59 var iconLoading = 'icon-spin animate-spin';
60 var iconSearch = 'icon-search';
60 var iconSearch = 'icon-search';
61 $('.files-filter-box-path i').removeClass(iconSearch).addClass(iconLoading);
61 $('.files-filter-box-path i').removeClass(iconSearch).addClass(iconLoading);
62 $filterInput.addClass('loading');
62 $filterInput.addClass('loading');
63
63
64 var callback = function (org) {
64 var callback = function (org) {
65 return function () {
65 return function () {
66 if ($filterInput.hasClass('init')) {
66 if ($filterInput.hasClass('init')) {
67 $filterInput.removeClass('init');
67 $filterInput.removeClass('init');
68 $filterInput.removeClass('loading');
68 $filterInput.removeClass('loading');
69 }
69 }
70 $('.files-filter-box-path i').removeClass(iconLoading).addClass(iconSearch);
70 $('.files-filter-box-path i').removeClass(iconLoading).addClass(iconSearch);
71
71
72 // auto re-filter if we filled in the input
72 // auto re-filter if we filled in the input
73 if (n_filter.value !== "") {
73 if (n_filter.value !== "") {
74 NodeFilter.updateFilter(n_filter, e)()
74 NodeFilter.updateFilter(n_filter, e)()
75 }
75 }
76
76
77 }
77 }
78 };
78 };
79 // load node data
79 // load node data
80 NodeFilter.fetchNodes(callback());
80 NodeFilter.fetchNodes(callback());
81
81
82 };
82 };
83
83
84 NodeFilter.resetFilter = function () {
84 NodeFilter.resetFilter = function () {
85 $('#tbody').show();
85 $('#tbody').show();
86 $('#tbody_filtered').hide();
86 $('#tbody_filtered').hide();
87 $filterInput.val('');
87 $filterInput.val('');
88 };
88 };
89
89
90 NodeFilter.handleKey = function (e) {
90 NodeFilter.handleKey = function (e) {
91 var scrollDown = function (element) {
91 var scrollDown = function (element) {
92 var elementBottom = element.offset().top + $(element).outerHeight();
92 var elementBottom = element.offset().top + $(element).outerHeight();
93 var windowBottom = window.innerHeight + $(window).scrollTop();
93 var windowBottom = window.innerHeight + $(window).scrollTop();
94 if (elementBottom > windowBottom) {
94 if (elementBottom > windowBottom) {
95 var offset = elementBottom - window.innerHeight;
95 var offset = elementBottom - window.innerHeight;
96 $('html,body').scrollTop(offset);
96 $('html,body').scrollTop(offset);
97 return false;
97 return false;
98 }
98 }
99 return true;
99 return true;
100 };
100 };
101
101
102 var scrollUp = function (element) {
102 var scrollUp = function (element) {
103 if (element.offset().top < $(window).scrollTop()) {
103 if (element.offset().top < $(window).scrollTop()) {
104 $('html,body').scrollTop(element.offset().top);
104 $('html,body').scrollTop(element.offset().top);
105 return false;
105 return false;
106 }
106 }
107 return true;
107 return true;
108 };
108 };
109 var $hlElem = $('.browser-highlight');
109 var $hlElem = $('.browser-highlight');
110
110
111 if (e.keyCode === 40) { // Down
111 if (e.keyCode === 40) { // Down
112 if ($hlElem.length === 0) {
112 if ($hlElem.length === 0) {
113 $('.browser-result').first().addClass('browser-highlight');
113 $('.browser-result').first().addClass('browser-highlight');
114 } else {
114 } else {
115 var next = $hlElem.next();
115 var next = $hlElem.next();
116 if (next.length !== 0) {
116 if (next.length !== 0) {
117 $hlElem.removeClass('browser-highlight');
117 $hlElem.removeClass('browser-highlight');
118 next.addClass('browser-highlight');
118 next.addClass('browser-highlight');
119 }
119 }
120 }
120 }
121
121
122 if ($hlElem.get(0) !== undefined){
122 if ($hlElem.get(0) !== undefined){
123 scrollDown($hlElem);
123 scrollDown($hlElem);
124 }
124 }
125 }
125 }
126 if (e.keyCode === 38) { // Up
126 if (e.keyCode === 38) { // Up
127 e.preventDefault();
127 e.preventDefault();
128 if ($hlElem.length !== 0) {
128 if ($hlElem.length !== 0) {
129 var next = $hlElem.prev();
129 var next = $hlElem.prev();
130 if (next.length !== 0) {
130 if (next.length !== 0) {
131 $('.browser-highlight').removeClass('browser-highlight');
131 $('.browser-highlight').removeClass('browser-highlight');
132 next.addClass('browser-highlight');
132 next.addClass('browser-highlight');
133 }
133 }
134 }
134 }
135
135
136 if ($hlElem.get(0) !== undefined){
136 if ($hlElem.get(0) !== undefined){
137 scrollUp($hlElem);
137 scrollUp($hlElem);
138 }
138 }
139
139
140 }
140 }
141 if (e.keyCode === 13) { // Enter
141 if (e.keyCode === 13) { // Enter
142 if ($('.browser-highlight').length !== 0) {
142 if ($('.browser-highlight').length !== 0) {
143 var url = $('.browser-highlight').find('.match-link').attr('href');
143 var url = $('.browser-highlight').find('.match-link').attr('href');
144 window.location = url;
144 window.location = url;
145 }
145 }
146 }
146 }
147 if (e.keyCode === 27) { // Esc
147 if (e.keyCode === 27) { // Esc
148 NodeFilter.resetFilter();
148 NodeFilter.resetFilter();
149 $('html,body').scrollTop(0);
149 $('html,body').scrollTop(0);
150 }
150 }
151
151
152 var capture_keys = [
152 var capture_keys = [
153 40, // ArrowDown
153 40, // ArrowDown
154 38, // ArrowUp
154 38, // ArrowUp
155 39, // ArrowRight
155 39, // ArrowRight
156 37, // ArrowLeft
156 37, // ArrowLeft
157 13, // Enter
157 13, // Enter
158 27 // Esc
158 27 // Esc
159 ];
159 ];
160
160
161 if ($.inArray(e.keyCode, capture_keys) === -1) {
161 if ($.inArray(e.keyCode, capture_keys) === -1) {
162 clearTimeout(NodeFilter.filterTimeout);
162 clearTimeout(NodeFilter.filterTimeout);
163 NodeFilter.filterTimeout = setTimeout(NodeFilter.updateFilter(n_filter, e), 200);
163 NodeFilter.filterTimeout = setTimeout(NodeFilter.updateFilter(n_filter, e), 200);
164 }
164 }
165
165
166 };
166 };
167
167
168 NodeFilter.fuzzy_match = function (filepath, query) {
168 NodeFilter.fuzzy_match = function (filepath, query) {
169 var highlight = [];
169 var highlight = [];
170 var order = 0;
170 var order = 0;
171 for (var i = 0; i < query.length; i++) {
171 for (var i = 0; i < query.length; i++) {
172 var match_position = filepath.indexOf(query[i]);
172 var match_position = filepath.indexOf(query[i]);
173 if (match_position !== -1) {
173 if (match_position !== -1) {
174 var prev_match_position = highlight[highlight.length - 1];
174 var prev_match_position = highlight[highlight.length - 1];
175 if (prev_match_position === undefined) {
175 if (prev_match_position === undefined) {
176 highlight.push(match_position);
176 highlight.push(match_position);
177 } else {
177 } else {
178 var current_match_position = prev_match_position + match_position + 1;
178 var current_match_position = prev_match_position + match_position + 1;
179 highlight.push(current_match_position);
179 highlight.push(current_match_position);
180 order = order + current_match_position - prev_match_position;
180 order = order + current_match_position - prev_match_position;
181 }
181 }
182 filepath = filepath.substring(match_position + 1);
182 filepath = filepath.substring(match_position + 1);
183 } else {
183 } else {
184 return false;
184 return false;
185 }
185 }
186 }
186 }
187 return {
187 return {
188 'order': order,
188 'order': order,
189 'highlight': highlight
189 'highlight': highlight
190 };
190 };
191 };
191 };
192
192
193 NodeFilter.sortPredicate = function (a, b) {
193 NodeFilter.sortPredicate = function (a, b) {
194 if (a.order < b.order) return -1;
194 if (a.order < b.order) return -1;
195 if (a.order > b.order) return 1;
195 if (a.order > b.order) return 1;
196 if (a.filepath < b.filepath) return -1;
196 if (a.filepath < b.filepath) return -1;
197 if (a.filepath > b.filepath) return 1;
197 if (a.filepath > b.filepath) return 1;
198 return 0;
198 return 0;
199 };
199 };
200
200
201 NodeFilter.updateFilter = function (elem, e) {
201 NodeFilter.updateFilter = function (elem, e) {
202 return function () {
202 return function () {
203 // Reset timeout
203 // Reset timeout
204 NodeFilter.filterTimeout = null;
204 NodeFilter.filterTimeout = null;
205 var query = elem.value.toLowerCase();
205 var query = elem.value.toLowerCase();
206 var match = [];
206 var match = [];
207 var matches_max = 20;
207 var matches_max = 20;
208 if (query !== "") {
208 if (query !== "") {
209 var results = [];
209 var results = [];
210 for (var k = 0; k < nodes.length; k++) {
210 for (var k = 0; k < nodes.length; k++) {
211 var result = NodeFilter.fuzzy_match(
211 var result = NodeFilter.fuzzy_match(
212 nodes[k].name.toLowerCase(), query);
212 nodes[k].name.toLowerCase(), query);
213 if (result) {
213 if (result) {
214 result.type = nodes[k].type;
214 result.type = nodes[k].type;
215 result.filepath = nodes[k].name;
215 result.filepath = nodes[k].name;
216 results.push(result);
216 results.push(result);
217 }
217 }
218 }
218 }
219 results = results.sort(NodeFilter.sortPredicate);
219 results = results.sort(NodeFilter.sortPredicate);
220 var limit = matches_max;
220 var limit = matches_max;
221 if (results.length < matches_max) {
221 if (results.length < matches_max) {
222 limit = results.length;
222 limit = results.length;
223 }
223 }
224 for (var i = 0; i < limit; i++) {
224 for (var i = 0; i < limit; i++) {
225 if (query && results.length > 0) {
225 if (query && results.length > 0) {
226 var n = results[i].filepath;
226 var n = results[i].filepath;
227 var t = results[i].type;
227 var t = results[i].type;
228 var n_hl = n.split("");
228 var n_hl = n.split("");
229 var pos = results[i].highlight;
229 var pos = results[i].highlight;
230 for (var j = 0; j < pos.length; j++) {
230 for (var j = 0; j < pos.length; j++) {
231 n_hl[pos[j]] = "<em>" + n_hl[pos[j]] + "</em>";
231 n_hl[pos[j]] = "<em>" + n_hl[pos[j]] + "</em>";
232 }
232 }
233 n_hl = n_hl.join("");
233 n_hl = n_hl.join("");
234 var new_url = url_base.replace('__FPATH__', n);
234 var new_url = url_base.replace('__FPATH__', n);
235
235
236 var typeObj = {
236 var typeObj = {
237 dir: 'icon-directory browser-dir',
237 dir: 'icon-directory browser-dir',
238 file: 'icon-file-text browser-file'
238 file: 'icon-file-text browser-file'
239 };
239 };
240
240
241 var typeIcon = '<i class="{0}"></i>'.format(typeObj[t]);
241 var typeIcon = '<i class="{0}"></i>'.format(typeObj[t]);
242 match.push('<tr class="browser-result"><td><a class="match-link" href="{0}">{1}{2}</a></td><td colspan="5"></td></tr>'.format(new_url, typeIcon, n_hl));
242 match.push('<tr class="browser-result"><td><a class="match-link" href="{0}">{1}{2}</a></td><td colspan="5"></td></tr>'.format(new_url, typeIcon, n_hl));
243 }
243 }
244 }
244 }
245 if (results.length > limit) {
245 if (results.length > limit) {
246 var truncated_count = results.length - matches_max;
246 var truncated_count = results.length - matches_max;
247 if (truncated_count === 1) {
247 if (truncated_count === 1) {
248 match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _gettext('truncated result')));
248 match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _gettext('truncated result')));
249 } else {
249 } else {
250 match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _gettext('truncated results')));
250 match.push('<tr><td>{0} {1}</td><td colspan="5"></td></tr>'.format(truncated_count, _gettext('truncated results')));
251 }
251 }
252 }
252 }
253 }
253 }
254 if (query !== "") {
254 if (query !== "") {
255 $('#tbody').hide();
255 $('#tbody').hide();
256 $('#tbody_filtered').show();
256 $('#tbody_filtered').show();
257
257
258 if (match.length === 0) {
258 if (match.length === 0) {
259 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_gettext('No matching files')));
259 match.push('<tr><td>{0}</td><td colspan="5"></td></tr>'.format(_gettext('No matching files')));
260 }
260 }
261 $('#tbody_filtered').html(match.join(""));
261 $('#tbody_filtered').html(match.join(""));
262 } else {
262 } else {
263 $('#tbody').show();
263 $('#tbody').show();
264 $('#tbody_filtered').hide();
264 $('#tbody_filtered').hide();
265 }
265 }
266
266
267 };
267 };
268 };
268 };
269
269
270 };
270 };
271
271
272 var getIdentNode = function(n){
272 var getIdentNode = function(n){
273 // iterate through nodes until matched interesting node
273 // iterate through nodes until matched interesting node
274 if (typeof n === 'undefined'){
274 if (typeof n === 'undefined'){
275 return -1;
275 return -1;
276 }
276 }
277 if(typeof n.id !== "undefined" && n.id.match('L[0-9]+')){
277 if(typeof n.id !== "undefined" && n.id.match('L[0-9]+')){
278 return n;
278 return n;
279 }
279 }
280 else{
280 else{
281 return getIdentNode(n.parentNode);
281 return getIdentNode(n.parentNode);
282 }
282 }
283 };
283 };
284
284
285 var getSelectionLink = function(e) {
285 var getSelectionLink = function(e) {
286 // get selection from start/to nodes
286 // get selection from start/to nodes
287 if (typeof window.getSelection !== "undefined") {
287 if (typeof window.getSelection !== "undefined") {
288 s = window.getSelection();
288 s = window.getSelection();
289
289
290 from = getIdentNode(s.anchorNode);
290 from = getIdentNode(s.anchorNode);
291 till = getIdentNode(s.focusNode);
291 till = getIdentNode(s.focusNode);
292
292
293 f_int = parseInt(from.id.replace('L',''));
293 f_int = parseInt(from.id.replace('L',''));
294 t_int = parseInt(till.id.replace('L',''));
294 t_int = parseInt(till.id.replace('L',''));
295
295
296 if (f_int > t_int){
296 if (f_int > t_int){
297 // highlight from bottom
297 // highlight from bottom
298 offset = -35;
298 offset = -35;
299 ranges = [t_int,f_int];
299 ranges = [t_int,f_int];
300 }
300 }
301 else{
301 else{
302 // highligth from top
302 // highligth from top
303 offset = 35;
303 offset = 35;
304 ranges = [f_int,t_int];
304 ranges = [f_int,t_int];
305 }
305 }
306 // if we select more than 2 lines
306 // if we select more than 2 lines
307 if (ranges[0] !== ranges[1]){
307 if (ranges[0] !== ranges[1]){
308 if($('#linktt').length === 0){
308 if($('#linktt').length === 0){
309 hl_div = document.createElement('div');
309 hl_div = document.createElement('div');
310 hl_div.id = 'linktt';
310 hl_div.id = 'linktt';
311 }
311 }
312 hl_div.innerHTML = '';
312 hl_div.innerHTML = '';
313
313
314 anchor = '#L'+ranges[0]+'-'+ranges[1];
314 anchor = '#L'+ranges[0]+'-'+ranges[1];
315 var link = document.createElement('a');
315 var link = document.createElement('a');
316 link.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
316 link.href = location.href.substring(0,location.href.indexOf('#'))+anchor;
317 link.innerHTML = _gettext('Selection link');
317 link.innerHTML = _gettext('Selection link');
318 hl_div.appendChild(link);
318 hl_div.appendChild(link);
319 $('#codeblock').append(hl_div);
319 $('#codeblock').append(hl_div);
320
320
321 var xy = $(till).offset();
321 var xy = $(till).offset();
322 $('#linktt').addClass('hl-tip-box tip-box');
322 $('#linktt').addClass('hl-tip-box tip-box');
323 $('#linktt').offset({top: xy.top + offset, left: xy.left});
323 $('#linktt').offset({top: xy.top + offset, left: xy.left});
324 $('#linktt').css('visibility','visible');
324 $('#linktt').css('visibility','visible');
325 }
325 }
326 else{
326 else{
327 $('#linktt').css('visibility','hidden');
327 $('#linktt').css('visibility','hidden');
328 }
328 }
329 }
329 }
330 };
330 };
331
331
332 var getFileState = function() {
332 var getFileState = function() {
333 // relies on a global set filesUrlData
333 // relies on a global set filesUrlData
334 var f_path = filesUrlData['f_path'];
334 var f_path = filesUrlData['f_path'];
335 var commit_id = filesUrlData['commit_id'];
335 var commit_id = filesUrlData['commit_id'];
336
336
337 var url_params = {
337 var url_params = {
338 repo_name: templateContext.repo_name,
338 repo_name: templateContext.repo_name,
339 commit_id: commit_id,
339 commit_id: commit_id,
340 f_path:'__FPATH__'
340 f_path:'__FPATH__'
341 };
341 };
342 if (atRef !== '') {
342 if (atRef !== '') {
343 url_params['at'] = atRef
343 url_params['at'] = atRef
344 }
344 }
345
345
346 var _url_base = pyroutes.url('repo_files', url_params);
346 var _url_base = pyroutes.url('repo_files', url_params);
347 var _node_list_url = pyroutes.url('repo_files_nodelist',
347 var _node_list_url = pyroutes.url('repo_files_nodelist',
348 {repo_name: templateContext.repo_name,
348 {repo_name: templateContext.repo_name,
349 commit_id: commit_id, f_path: f_path});
349 commit_id: commit_id, f_path: f_path});
350
350
351 return {
351 return {
352 f_path: f_path,
352 f_path: f_path,
353 commit_id: commit_id,
353 commit_id: commit_id,
354 node_list_url: _node_list_url,
354 node_list_url: _node_list_url,
355 url_base: _url_base
355 url_base: _url_base
356 };
356 };
357 };
357 };
358
358
359 var getFilesMetadata = function() {
359 var getFilesMetadata = function() {
360 // relies on metadataRequest global state
360 // relies on metadataRequest global state
361 if (metadataRequest && metadataRequest.readyState != 4) {
361 if (metadataRequest && metadataRequest.readyState != 4) {
362 metadataRequest.abort();
362 metadataRequest.abort();
363 }
363 }
364
364
365 if ($('#file-tree-wrapper').hasClass('full-load')) {
365 if ($('#file-tree-wrapper').hasClass('full-load')) {
366 // in case our HTML wrapper has full-load class we don't
366 // in case our HTML wrapper has full-load class we don't
367 // trigger the async load of metadata
367 // trigger the async load of metadata
368 return false;
368 return false;
369 }
369 }
370
370
371 var state = getFileState();
371 var state = getFileState();
372 var url_data = {
372 var url_data = {
373 'repo_name': templateContext.repo_name,
373 'repo_name': templateContext.repo_name,
374 'commit_id': state.commit_id,
374 'commit_id': state.commit_id,
375 'f_path': state.f_path,
375 'f_path': state.f_path,
376 };
376 };
377
377
378 if (atRef !== '') {
378 if (atRef !== '') {
379 url_data['at'] = atRef
379 url_data['at'] = atRef
380 }
380 }
381
381
382 var url = pyroutes.url('repo_nodetree_full', url_data);
382 var url = pyroutes.url('repo_nodetree_full', url_data);
383
383
384 metadataRequest = $.ajax({url: url});
384 metadataRequest = $.ajax({url: url});
385
385
386 metadataRequest.done(function(data) {
386 metadataRequest.done(function(data) {
387 $('#file-tree').html(data);
387 $('#file-tree').html(data);
388 timeagoActivate();
388 timeagoActivate();
389 tooltipActivate();
389 tooltipActivate();
390 });
390 });
391 metadataRequest.fail(function (data, textStatus, errorThrown) {
391 metadataRequest.fail(function (data, textStatus, errorThrown) {
392 if (data.status != 0) {
392 if (data.status != 0) {
393 alert("Error while fetching metadata.\nError code {0} ({1}).Please consider reloading the page".format(data.status,data.statusText));
393 alert("Error while fetching metadata.\nError code {0} ({1}).Please consider reloading the page".format(data.status,data.statusText));
394 }
394 }
395 });
395 });
396 };
396 };
397
397
398 // show more authors
398 // show more authors
399 var showAuthors = function(elem, annotate) {
399 var showAuthors = function(elem, annotate) {
400 var state = getFileState('callbacks');
400 var state = getFileState('callbacks');
401
401
402 var url = pyroutes.url('repo_file_authors',
402 var url = pyroutes.url('repo_file_authors',
403 {'repo_name': templateContext.repo_name,
403 {'repo_name': templateContext.repo_name,
404 'commit_id': state.commit_id, 'f_path': state.f_path});
404 'commit_id': state.commit_id, 'f_path': state.f_path});
405
405
406 $.pjax({
406 $.pjax({
407 url: url,
407 url: url,
408 data: 'annotate={0}'.format(annotate),
408 data: 'annotate={0}'.format(annotate),
409 container: '#file_authors',
409 container: '#file_authors',
410 push: false,
410 push: false,
411 timeout: 5000
411 timeout: 5000
412 }).complete(function(){
412 }).complete(function(){
413 $(elem).hide();
413 $(elem).hide();
414 $('#file_authors_title').html(_gettext('All Authors'));
414 $('#file_authors_title').html(_gettext('All Authors'));
415 tooltipActivate();
415 tooltipActivate();
416 })
416 })
417 };
417 };
418
418
419
419
420 (function (mod) {
420 (function (mod) {
421
421
422 if (typeof exports == "object" && typeof module == "object") {
422 if (typeof exports == "object" && typeof module == "object") {
423 // CommonJS
423 // CommonJS
424 module.exports = mod();
424 module.exports = mod();
425 } else {
425 } else {
426 // Plain browser env
426 // Plain browser env
427 (this || window).FileEditor = mod();
427 (this || window).FileEditor = mod();
428 }
428 }
429
429
430 })(function () {
430 })(function () {
431 "use strict";
431 "use strict";
432
432
433 function FileEditor(textAreaElement, options) {
433 function FileEditor(textAreaElement, options) {
434 if (!(this instanceof FileEditor)) {
434 if (!(this instanceof FileEditor)) {
435 return new FileEditor(textAreaElement, options);
435 return new FileEditor(textAreaElement, options);
436 }
436 }
437 // bind the element instance to our Form
437 // bind the element instance to our Form
438 var te = $(textAreaElement).get(0);
438 var te = $(textAreaElement).get(0);
439 if (te !== undefined) {
439 if (te !== undefined) {
440 te.FileEditor = this;
440 te.FileEditor = this;
441 }
441 }
442
442
443 this.modes_select = '#set_mode';
443 this.modes_select = '#set_mode';
444 this.filename_selector = '#filename';
444 this.filename_selector = '#filename';
445 this.commit_btn_selector = '#commit_btn';
445 this.commit_btn_selector = '#commit_btn';
446 this.line_wrap_selector = '#line_wrap';
446 this.line_wrap_selector = '#line_wrap';
447 this.editor_preview_selector = '#editor_preview';
447 this.editor_preview_selector = '#editor_preview';
448
448
449 if (te !== undefined) {
449 if (te !== undefined) {
450 this.cm = initCodeMirror(textAreaElement, null, false);
450 this.cm = initCodeMirror(textAreaElement, null, false);
451 }
451 }
452
452
453 // FUNCTIONS and helpers
453 // FUNCTIONS and helpers
454 var self = this;
454 var self = this;
455
455
456 this.submitHandler = function() {
456 this.submitHandler = function() {
457 $(self.commit_btn_selector).on('click', function(e) {
457 $(self.commit_btn_selector).on('click', function(e) {
458
458
459 var filename = $(self.filename_selector).val();
459 var filename = $(self.filename_selector).val();
460 if (filename === "") {
460 if (filename === "") {
461 alert("Missing filename");
461 alert("Missing filename");
462 e.preventDefault();
462 e.preventDefault();
463 }
463 }
464
464
465 var button = $(this);
465 var button = $(this);
466 if (button.hasClass('clicked')) {
466 if (button.hasClass('clicked')) {
467 button.attr('disabled', true);
467 button.attr('disabled', true);
468 } else {
468 } else {
469 button.addClass('clicked');
469 button.addClass('clicked');
470 }
470 }
471 });
471 });
472 };
472 };
473 this.submitHandler();
473 this.submitHandler();
474
474
475 // on select line wraps change the editor
475 // on select line wraps change the editor
476 this.lineWrapHandler = function () {
476 this.lineWrapHandler = function () {
477 $(self.line_wrap_selector).on('change', function (e) {
477 $(self.line_wrap_selector).on('change', function (e) {
478 var selected = e.currentTarget;
478 var selected = e.currentTarget;
479 var line_wraps = {'on': true, 'off': false}[selected.value];
479 var line_wraps = {'on': true, 'off': false}[selected.value];
480 setCodeMirrorLineWrap(self.cm, line_wraps)
480 setCodeMirrorLineWrap(self.cm, line_wraps)
481 });
481 });
482 };
482 };
483 this.lineWrapHandler();
483 this.lineWrapHandler();
484
484
485
485
486 this.showPreview = function () {
486 this.showPreview = function () {
487
487
488 var _text = self.cm.getValue();
488 var _text = self.cm.getValue();
489 var _file_path = $(self.filename_selector).val();
489 var _file_path = $(self.filename_selector).val();
490 if (_text && _file_path) {
490 if (_text && _file_path) {
491 $('.show-preview').addClass('active');
491 $('.show-preview').addClass('active');
492 $('.show-editor').removeClass('active');
492 $('.show-editor').removeClass('active');
493
493
494 $(self.editor_preview_selector).show();
494 $(self.editor_preview_selector).show();
495 $(self.cm.getWrapperElement()).hide();
495 $(self.cm.getWrapperElement()).hide();
496
496
497
497
498 var post_data = {'text': _text, 'file_path': _file_path, 'csrf_token': CSRF_TOKEN};
498 var post_data = {'text': _text, 'file_path': _file_path, 'csrf_token': CSRF_TOKEN};
499 $(self.editor_preview_selector).html(_gettext('Loading ...'));
499 $(self.editor_preview_selector).html(_gettext('Loading ...'));
500
500
501 var url = pyroutes.url('file_preview');
501 var url = pyroutes.url('file_preview');
502
502
503 ajaxPOST(url, post_data, function (o) {
503 ajaxPOST(url, post_data, function (o) {
504 $(self.editor_preview_selector).html(o);
504 $(self.editor_preview_selector).html(o);
505 })
505 })
506 }
506 }
507
507
508 };
508 };
509
509
510 this.showEditor = function () {
510 this.showEditor = function () {
511 $(self.editor_preview_selector).hide();
511 $(self.editor_preview_selector).hide();
512 $('.show-editor').addClass('active');
512 $('.show-editor').addClass('active');
513 $('.show-preview').removeClass('active');
513 $('.show-preview').removeClass('active');
514
514
515 $(self.cm.getWrapperElement()).show();
515 $(self.cm.getWrapperElement()).show();
516 };
516 };
517
517
518
518
519 }
519 }
520
520
521 return FileEditor;
521 return FileEditor;
522 });
522 });
523
523
524
525 var checkFileHead = function($editForm, commit_id, f_path, operation) {
526 function getFormData($form){
527 var unindexed_array = $form.serializeArray();
528 var indexed_array = {};
529
530 $.map(unindexed_array, function(n, i){
531 indexed_array[n['name']] = n['value'];
532 });
533
534 return indexed_array;
535 }
536
537 $editForm.on('submit', function (e) {
538
539 var validHead = $editForm.find('#commit_btn').data('validHead');
540 if (validHead === true){
541 return true
542 }
543
544 // no marker, we do "checks"
545 e.preventDefault();
546 var formData = getFormData($editForm);
547 var new_path = formData['filename'];
548
549 var success = function(data) {
550
551 if (data['is_head'] === true && data['path_exists'] === "") {
552
553 $editForm.find('#commit_btn').data('validHead', true);
554 $editForm.find('#commit_btn').val('Committing...');
555 $editForm.submit();
556
557 } else {
558 var message = '';
559 var urlTmpl = '<a target="_blank" href="{0}">here</a>';
560 $editForm.find('#commit_btn').val('Commit aborted');
561
562 if (operation === 'edit') {
563 var new_url = urlTmpl.format(pyroutes.url('repo_files_edit_file', {"repo_name": templateContext.repo_name, "commit_id": data['branch'], "f_path": f_path}));
564 message = _gettext('File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.'.format(f_path, new_url));
565 } else if (operation === 'delete') {
566 var new_url = urlTmpl.format(pyroutes.url('repo_files_remove_file', {"repo_name": templateContext.repo_name, "commit_id": data['branch'], "f_path": f_path}));
567 message = _gettext('File `{0}` has a newer version available, or has been removed. Click {1} to see the latest version.'.format(f_path, new_url));
568 } else if (operation === 'create') {
569 if (data['path_exists'] !== "") {
570 message = _gettext('There is an existing path `{0}` at this commit.'.format(data['path_exists']));
571 } else {
572 var new_url = urlTmpl.format(pyroutes.url('repo_files_add_file', {"repo_name": templateContext.repo_name, "commit_id": data['branch'], "f_path": f_path, "filename": new_path}));
573 message = _gettext('There is a later version of file tree available. Click {0} to create a file at the latest tree.'.format(new_url));
574 }
575 }
576
577 var payload = {
578 message: {
579 message: message,
580 level: 'warning',
581 force: true
582 }
583 };
584 $.Topic('/notifications').publish(payload);
585 }
586 };
587
588 // lock button
589 $editForm.find('#commit_btn').attr('disabled', 'disabled');
590 $editForm.find('#commit_btn').val('Checking commit...');
591
592 var postData = {'csrf_token': CSRF_TOKEN, 'path': new_path, 'operation': operation};
593 ajaxPOST(pyroutes.url('repo_files_check_head',
594 {'repo_name': templateContext.repo_name, 'commit_id': commit_id, 'f_path': f_path}),
595 postData, success);
596
597 return false
598
599 });
600 };
@@ -1,114 +1,117 b''
1 <%inherit file="/base/base.mako"/>
1 <%inherit file="/base/base.mako"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('{} Files Add').format(c.repo_name)}
4 ${_('{} Files Add').format(c.repo_name)}
5 %if c.rhodecode_name:
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
7 %endif
8 </%def>
8 </%def>
9
9
10 <%def name="menu_bar_nav()">
10 <%def name="menu_bar_nav()">
11 ${self.menu_items(active='repositories')}
11 ${self.menu_items(active='repositories')}
12 </%def>
12 </%def>
13
13
14 <%def name="breadcrumbs_links()"></%def>
14 <%def name="breadcrumbs_links()"></%def>
15
15
16 <%def name="menu_bar_subnav()">
16 <%def name="menu_bar_subnav()">
17 ${self.repo_menu(active='files')}
17 ${self.repo_menu(active='files')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21
21
22 <div class="box">
22 <div class="box">
23
23
24 <div class="edit-file-title">
24 <div class="edit-file-title">
25 <span class="title-heading">${_('Add new file')} @ <code>${h.show_id(c.commit)}</code></span>
25 <span class="title-heading">${_('Add new file')} @ <code>${h.show_id(c.commit)}</code></span>
26 % if c.commit.branch:
26 % if c.commit.branch:
27 <span class="tag branchtag">
27 <span class="tag branchtag">
28 <i class="icon-branch"></i> ${c.commit.branch}
28 <i class="icon-branch"></i> ${c.commit.branch}
29 </span>
29 </span>
30 % endif
30 % endif
31 </div>
31 </div>
32
32
33 ${h.secure_form(h.route_path('repo_files_create_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
33 ${h.secure_form(h.route_path('repo_files_create_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
34 <div class="edit-file-fieldset">
34 <div class="edit-file-fieldset">
35 <div class="path-items">
35 <div class="path-items">
36 <ul>
36 <ul>
37 <li class="breadcrumb-path">
37 <li class="breadcrumb-path">
38 <div>
38 <div>
39 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
39 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
40 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path)}">${c.f_path}</a> ${('/' if c.f_path else '')}
40 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path)}">${c.f_path}</a> ${('/' if c.f_path else '')}
41 </div>
41 </div>
42 </li>
42 </li>
43 <li class="location-path">
43 <li class="location-path">
44 <input class="file-name-input input-small" type="text" value="" name="filename" id="filename" placeholder="${_('Filename e.g example.py, or docs/readme.md')}">
44 <input class="file-name-input input-small" type="text" value="${request.GET.get('filename')}" name="filename" id="filename" placeholder="${_('Filename e.g example.py, or docs/readme.md')}">
45 </li>
45 </li>
46 </ul>
46 </ul>
47 </div>
47 </div>
48
48
49 </div>
49 </div>
50
50
51 <div class="table">
51 <div class="table">
52 <div>
52 <div>
53
54 <div id="codeblock" class="codeblock">
53 <div id="codeblock" class="codeblock">
55 <div class="editor-items">
54 <div class="editor-items">
56 <div class="editor-action active show-editor pull-left" onclick="fileEditor.showEditor(); return false">
55 <div class="editor-action active show-editor pull-left" onclick="fileEditor.showEditor(); return false">
57 ${_('Edit')}
56 ${_('Edit')}
58 </div>
57 </div>
59
58
60 <div class="editor-action show-preview pull-left" onclick="fileEditor.showPreview(); return false">
59 <div class="editor-action show-preview pull-left" onclick="fileEditor.showPreview(); return false">
61 ${_('Preview')}
60 ${_('Preview')}
62 </div>
61 </div>
63
62
64 <div class="pull-right">
63 <div class="pull-right">
65 ${h.dropdownmenu('line_wrap', 'off', [('on', _('Line wraps on')), ('off', _('line wraps off'))], extra_classes=['last-item'])}
64 ${h.dropdownmenu('line_wrap', 'off', [('on', _('Line wraps on')), ('off', _('line wraps off'))], extra_classes=['last-item'])}
66 </div>
65 </div>
67 <div class="pull-right">
66 <div class="pull-right">
68 ${h.dropdownmenu('set_mode','plain',[('plain', _('plain'))], enable_filter=True)}
67 ${h.dropdownmenu('set_mode','plain',[('plain', _('plain'))], enable_filter=True)}
69 </div>
68 </div>
70 </div>
69 </div>
71
70
72 <div id="editor_container">
71 <div id="editor_container">
73 <pre id="editor_pre"></pre>
72 <pre id="editor_pre"></pre>
74 <textarea id="editor" name="content" ></textarea>
73 <textarea id="editor" name="content" ></textarea>
75 <div id="editor_preview"></div>
74 <div id="editor_preview"></div>
76 </div>
75 </div>
77 </div>
76 </div>
78 </div>
77 </div>
79 </div>
78 </div>
80
79
81 <div class="edit-file-fieldset">
80 <div class="edit-file-fieldset">
82 <div class="fieldset">
81 <div class="fieldset">
83 <div class="message">
82 <div class="message">
84 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
83 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
85 </div>
84 </div>
86 </div>
85 </div>
87 <div class="pull-left">
86 <div class="pull-left">
88 ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
87 ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
89 </div>
88 </div>
90 </div>
89 </div>
91 ${h.end_form()}
90 ${h.end_form()}
92 </div>
91 </div>
93
92
94 <script type="text/javascript">
93 <script type="text/javascript">
95
94
96 $(document).ready(function () {
95 $(document).ready(function () {
97 var modes_select = $('#set_mode');
96 var modes_select = $('#set_mode');
98 var filename_selector = '#filename';
97 var filename_selector = '#filename';
99 fillCodeMirrorOptions(modes_select);
98 fillCodeMirrorOptions(modes_select);
100
99
101 fileEditor = new FileEditor('#editor');
100 fileEditor = new FileEditor('#editor');
102
101
103 // on change of select field set mode
102 // on change of select field set mode
104 setCodeMirrorModeFromSelect(modes_select, filename_selector, fileEditor.cm, null);
103 setCodeMirrorModeFromSelect(modes_select, filename_selector, fileEditor.cm, null);
105
104
106 // on entering the new filename set mode, from given extension
105 // on entering the new filename set mode, from given extension
107 setCodeMirrorModeFromInput(modes_select, filename_selector, fileEditor.cm, null);
106 setCodeMirrorModeFromInput(modes_select, filename_selector, fileEditor.cm, null);
108
107
109 $('#filename').focus();
108 $('#filename').focus();
110
109
110 var commit_id = "${c.commit.raw_id}";
111 var f_path = "${c.f_path}";
112
113 checkFileHead($('#eform'), commit_id, f_path, 'create')
111 });
114 });
112
115
113 </script>
116 </script>
114 </%def>
117 </%def>
@@ -1,89 +1,93 b''
1 <%inherit file="/base/base.mako"/>
1 <%inherit file="/base/base.mako"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('{} Files Delete').format(c.repo_name)}
4 ${_('{} Files Delete').format(c.repo_name)}
5 %if c.rhodecode_name:
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
7 %endif
8 </%def>
8 </%def>
9
9
10 <%def name="menu_bar_nav()">
10 <%def name="menu_bar_nav()">
11 ${self.menu_items(active='repositories')}
11 ${self.menu_items(active='repositories')}
12 </%def>
12 </%def>
13
13
14 <%def name="breadcrumbs_links()"></%def>
14 <%def name="breadcrumbs_links()"></%def>
15
15
16 <%def name="menu_bar_subnav()">
16 <%def name="menu_bar_subnav()">
17 ${self.repo_menu(active='files')}
17 ${self.repo_menu(active='files')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21
21
22 <div class="box">
22 <div class="box">
23
23
24 <div class="edit-file-title">
24 <div class="edit-file-title">
25 <span class="title-heading">${_('Delete file')} @ <code>${h.show_id(c.commit)}</code></span>
25 <span class="title-heading">${_('Delete file')} @ <code>${h.show_id(c.commit)}</code></span>
26 % if c.commit.branch:
26 % if c.commit.branch:
27 <span class="tag branchtag">
27 <span class="tag branchtag">
28 <i class="icon-branch"></i> ${c.commit.branch}
28 <i class="icon-branch"></i> ${c.commit.branch}
29 </span>
29 </span>
30 % endif
30 % endif
31 </div>
31 </div>
32
32
33 ${h.secure_form(h.route_path('repo_files_delete_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
33 ${h.secure_form(h.route_path('repo_files_delete_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
34 <div class="edit-file-fieldset">
34 <div class="edit-file-fieldset">
35 <div class="path-items">
35 <div class="path-items">
36 <li class="breadcrumb-path">
36 <li class="breadcrumb-path">
37 <div>
37 <div>
38 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
38 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
39 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.file.dir_path)}">${c.file.dir_path}</a> ${('/' if c.file.dir_path else '')}
39 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.file.dir_path)}">${c.file.dir_path}</a> ${('/' if c.file.dir_path else '')}
40 </div>
40 </div>
41 </li>
41 </li>
42 <li class="location-path">
42 <li class="location-path">
43 <input type="hidden" value="${c.f_path}" name="root_path">
43 <input type="hidden" value="${c.f_path}" name="root_path">
44 <input class="file-name-input input-small" type="text" value="${c.file.name}" name="filename" id="filename" disabled="disabled">
44 <input class="file-name-input input-small" type="text" value="${c.file.name}" name="filename" id="filename" disabled="disabled">
45 </li>
45 </li>
46 </div>
46 </div>
47
47
48 </div>
48 </div>
49
49
50 <div id="codeblock" class="codeblock delete-file-preview">
50 <div id="codeblock" class="codeblock delete-file-preview">
51 <div class="code-body">
51 <div class="code-body">
52 %if c.file.is_binary:
52 %if c.file.is_binary:
53 ${_('Binary file (%s)') % c.file.mimetype}
53 ${_('Binary file (%s)') % c.file.mimetype}
54 %else:
54 %else:
55 %if c.file.size < c.visual.cut_off_limit_file:
55 %if c.file.size < c.visual.cut_off_limit_file:
56 ${h.pygmentize(c.file,linenos=True,anchorlinenos=False,cssclass="code-highlight")}
56 ${h.pygmentize(c.file,linenos=True,anchorlinenos=False,cssclass="code-highlight")}
57 %else:
57 %else:
58 ${_('File size {} is bigger then allowed limit {}. ').format(h.format_byte_size_binary(c.file.size), h.format_byte_size_binary(c.visual.cut_off_limit_file))} ${h.link_to(_('Show as raw'),
58 ${_('File size {} is bigger then allowed limit {}. ').format(h.format_byte_size_binary(c.file.size), h.format_byte_size_binary(c.visual.cut_off_limit_file))} ${h.link_to(_('Show as raw'),
59 h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
59 h.route_path('repo_file_raw',repo_name=c.repo_name,commit_id=c.commit.raw_id,f_path=c.f_path))}
60 %endif
60 %endif
61 %endif
61 %endif
62 </div>
62 </div>
63 </div>
63 </div>
64
64
65 <div class="edit-file-fieldset">
65 <div class="edit-file-fieldset">
66 <div class="fieldset">
66 <div class="fieldset">
67 <div class="message">
67 <div class="message">
68 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
68 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
69 </div>
69 </div>
70 </div>
70 </div>
71 <div class="pull-left">
71 <div class="pull-left">
72 ${h.submit('commit',_('Commit changes'),class_="btn btn-small btn-danger-action")}
72 ${h.submit('commit_btn',_('Commit changes'),class_="btn btn-small btn-danger-action")}
73 </div>
73 </div>
74 </div>
74 </div>
75 ${h.end_form()}
75 ${h.end_form()}
76 </div>
76 </div>
77
77
78
78
79 <script type="text/javascript">
79 <script type="text/javascript">
80
80
81 $(document).ready(function () {
81 $(document).ready(function () {
82
82
83 fileEditor = new FileEditor('#editor');
83 fileEditor = new FileEditor('#editor');
84
84
85 var commit_id = "${c.commit.raw_id}";
86 var f_path = "${c.f_path}";
87
88 checkFileHead($('#eform'), commit_id, f_path, 'delete');
85 });
89 });
86
90
87 </script>
91 </script>
88
92
89 </%def>
93 </%def>
@@ -1,124 +1,129 b''
1 <%inherit file="/base/base.mako"/>
1 <%inherit file="/base/base.mako"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('{} Files Edit').format(c.repo_name)}
4 ${_('{} Files Edit').format(c.repo_name)}
5 %if c.rhodecode_name:
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
7 %endif
8 </%def>
8 </%def>
9
9
10 <%def name="menu_bar_nav()">
10 <%def name="menu_bar_nav()">
11 ${self.menu_items(active='repositories')}
11 ${self.menu_items(active='repositories')}
12 </%def>
12 </%def>
13
13
14 <%def name="breadcrumbs_links()"></%def>
14 <%def name="breadcrumbs_links()"></%def>
15
15
16 <%def name="menu_bar_subnav()">
16 <%def name="menu_bar_subnav()">
17 ${self.repo_menu(active='files')}
17 ${self.repo_menu(active='files')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21
21
22 <div class="box">
22 <div class="box">
23
23
24 <div class="edit-file-title">
24 <div class="edit-file-title">
25 <span class="title-heading">${_('Edit file')} @ <code>${h.show_id(c.commit)}</code></span>
25 <span class="title-heading">${_('Edit file')} @ <code>${h.show_id(c.commit)}</code></span>
26 % if c.commit.branch:
26 % if c.commit.branch:
27 <span class="tag branchtag">
27 <span class="tag branchtag">
28 <i class="icon-branch"></i> ${c.commit.branch}
28 <i class="icon-branch"></i> ${c.commit.branch}
29 </span>
29 </span>
30 % endif
30 % endif
31 </div>
31 </div>
32
32
33 ${h.secure_form(h.route_path('repo_files_update_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
33 ${h.secure_form(h.route_path('repo_files_update_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path), id='eform', request=request)}
34 <div class="edit-file-fieldset">
34 <div class="edit-file-fieldset">
35 <div class="path-items">
35 <div class="path-items">
36 <ul>
36 <ul>
37 <li class="breadcrumb-path">
37 <li class="breadcrumb-path">
38 <div>
38 <div>
39 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
39 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
40 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.file.dir_path)}">${c.file.dir_path}</a> ${('/' if c.file.dir_path else '')}
40 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.file.dir_path)}">${c.file.dir_path}</a> ${('/' if c.file.dir_path else '')}
41 </div>
41 </div>
42 </li>
42 </li>
43 <li class="location-path">
43 <li class="location-path">
44 <input type="hidden" value="${c.f_path}" name="root_path">
44 <input type="hidden" value="${c.f_path}" name="root_path">
45 <input class="file-name-input input-small" type="text" value="${c.file.name}" name="filename" id="filename" placeholder="${_('Filename e.g example.py, or docs/readme.md')}">
45 <input class="file-name-input input-small" type="text" value="${c.file.name}" name="filename" id="filename" placeholder="${_('Filename e.g example.py, or docs/readme.md')}">
46 </li>
46 </li>
47 </ul>
47 </ul>
48 </div>
48 </div>
49
49
50 </div>
50 </div>
51
51
52 <div class="table">
52 <div class="table">
53 <div>
53 <div>
54
54
55 <div id="codeblock" class="codeblock">
55 <div id="codeblock" class="codeblock">
56 <div class="editor-items">
56 <div class="editor-items">
57 <div class="editor-action active show-editor pull-left" onclick="fileEditor.showEditor(); return false">
57 <div class="editor-action active show-editor pull-left" onclick="fileEditor.showEditor(); return false">
58 ${_('Edit')}
58 ${_('Edit')}
59 </div>
59 </div>
60
60
61 <div class="editor-action show-preview pull-left" onclick="fileEditor.showPreview(); return false">
61 <div class="editor-action show-preview pull-left" onclick="fileEditor.showPreview(); return false">
62 ${_('Preview')}
62 ${_('Preview')}
63 </div>
63 </div>
64
64
65 <div class="pull-right">
65 <div class="pull-right">
66 ${h.dropdownmenu('line_wrap', 'off', [('on', _('Line wraps on')), ('off', _('line wraps off')),])}
66 ${h.dropdownmenu('line_wrap', 'off', [('on', _('Line wraps on')), ('off', _('line wraps off')),])}
67 </div>
67 </div>
68 <div class="pull-right">
68 <div class="pull-right">
69 ${h.dropdownmenu('set_mode','plain',[('plain', _('plain'))],enable_filter=True)}
69 ${h.dropdownmenu('set_mode','plain',[('plain', _('plain'))],enable_filter=True)}
70 </div>
70 </div>
71 </div>
71 </div>
72
72
73 <div id="editor_container">
73 <div id="editor_container">
74 <pre id="editor_pre"></pre>
74 <pre id="editor_pre"></pre>
75 <textarea id="editor" name="content" >${h.escape(c.file.content)|n}</textarea>
75 <textarea id="editor" name="content" >${h.escape(c.file.content)|n}</textarea>
76 <div id="editor_preview" ></div>
76 <div id="editor_preview" ></div>
77 </div>
77 </div>
78 </div>
78 </div>
79 </div>
79 </div>
80 </div>
80 </div>
81
81
82 <div class="edit-file-fieldset">
82 <div class="edit-file-fieldset">
83 <div class="fieldset">
83 <div class="fieldset">
84 <div class="message">
84 <div class="message">
85 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
85 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
86 </div>
86 </div>
87 </div>
87 </div>
88 <div class="pull-left">
88 <div class="pull-left">
89 ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
89 ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
90 </div>
90 </div>
91 </div>
91 </div>
92 ${h.end_form()}
92 ${h.end_form()}
93 </div>
93 </div>
94
94
95 <script type="text/javascript">
95 <script type="text/javascript">
96
96
97 $(document).ready(function() {
97 $(document).ready(function() {
98 var modes_select = $('#set_mode');
98 var modes_select = $('#set_mode');
99 var filename_selector = '#filename';
99 var filename_selector = '#filename';
100 fillCodeMirrorOptions(modes_select);
100 fillCodeMirrorOptions(modes_select);
101
101
102 fileEditor = new FileEditor('#editor');
102 fileEditor = new FileEditor('#editor');
103
103
104 // try to detect the mode based on the file we edit
104 // try to detect the mode based on the file we edit
105 var detected_mode = detectCodeMirrorMode("${c.file.name}", "${c.file.mimetype}");
105 var detected_mode = detectCodeMirrorMode("${c.file.name}", "${c.file.mimetype}");
106
106
107 if (detected_mode) {
107 if (detected_mode) {
108 setCodeMirrorMode(fileEditor.cm, detected_mode);
108 setCodeMirrorMode(fileEditor.cm, detected_mode);
109
109
110 var mimetype = $(modes_select).find("option[mode={0}]".format(detected_mode)).val();
110 var mimetype = $(modes_select).find("option[mode={0}]".format(detected_mode)).val();
111 $(modes_select).select2("val", mimetype).trigger('change');
111 $(modes_select).select2("val", mimetype).trigger('change');
112 }
112 }
113
113
114 // on change of select field set mode
114 // on change of select field set mode
115 setCodeMirrorModeFromSelect(modes_select, filename_selector, fileEditor.cm, null);
115 setCodeMirrorModeFromSelect(modes_select, filename_selector, fileEditor.cm, null);
116
116
117 // on entering the new filename set mode, from given extension
117 // on entering the new filename set mode, from given extension
118 setCodeMirrorModeFromInput(modes_select, filename_selector, fileEditor.cm, null);
118 setCodeMirrorModeFromInput(modes_select, filename_selector, fileEditor.cm, null);
119
119
120 var commit_id = "${c.commit.raw_id}";
121 var f_path = "${c.f_path}";
122
123 checkFileHead($('#eform'), commit_id, f_path, 'edit')
124
120 });
125 });
121
126
122
127
123 </script>
128 </script>
124 </%def>
129 </%def>
@@ -1,211 +1,211 b''
1 <%inherit file="/base/base.mako"/>
1 <%inherit file="/base/base.mako"/>
2
2
3 <%def name="title()">
3 <%def name="title()">
4 ${_('{} Files Upload').format(c.repo_name)}
4 ${_('{} Files Upload').format(c.repo_name)}
5 %if c.rhodecode_name:
5 %if c.rhodecode_name:
6 &middot; ${h.branding(c.rhodecode_name)}
6 &middot; ${h.branding(c.rhodecode_name)}
7 %endif
7 %endif
8 </%def>
8 </%def>
9
9
10 <%def name="menu_bar_nav()">
10 <%def name="menu_bar_nav()">
11 ${self.menu_items(active='repositories')}
11 ${self.menu_items(active='repositories')}
12 </%def>
12 </%def>
13
13
14 <%def name="breadcrumbs_links()"></%def>
14 <%def name="breadcrumbs_links()"></%def>
15
15
16 <%def name="menu_bar_subnav()">
16 <%def name="menu_bar_subnav()">
17 ${self.repo_menu(active='files')}
17 ${self.repo_menu(active='files')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21
21
22 <div class="box">
22 <div class="box">
23 ## Template for uploads
23 ## Template for uploads
24 <div style="display: none" id="tpl-dropzone">
24 <div style="display: none" id="tpl-dropzone">
25 <div class="dz-preview dz-file-preview">
25 <div class="dz-preview dz-file-preview">
26 <div class="dz-details">
26 <div class="dz-details">
27
27
28 <div class="dz-filename">
28 <div class="dz-filename">
29 <span data-dz-name></span>
29 <span data-dz-name></span>
30 </div>
30 </div>
31 <div class="dz-filename-size">
31 <div class="dz-filename-size">
32 <span class="dz-size" data-dz-size></span>
32 <span class="dz-size" data-dz-size></span>
33
33
34 </div>
34 </div>
35
35
36 <div class="dz-sending" style="display: none">${_('Uploading...')}</div>
36 <div class="dz-sending" style="display: none">${_('Uploading...')}</div>
37 <div class="dz-response" style="display: none">
37 <div class="dz-response" style="display: none">
38 ${_('Uploaded')} 100%
38 ${_('Uploaded')} 100%
39 </div>
39 </div>
40
40
41 </div>
41 </div>
42 <div class="dz-progress">
42 <div class="dz-progress">
43 <span class="dz-upload" data-dz-uploadprogress></span>
43 <span class="dz-upload" data-dz-uploadprogress></span>
44 </div>
44 </div>
45
45
46 <div class="dz-error-message">
46 <div class="dz-error-message">
47 </div>
47 </div>
48 </div>
48 </div>
49 </div>
49 </div>
50
50
51 <div class="edit-file-title">
51 <div class="edit-file-title">
52 <span class="title-heading">${_('Upload new file')} @ <code>${h.show_id(c.commit)}</code></span>
52 <span class="title-heading">${_('Upload new file')} @ <code>${h.show_id(c.commit)}</code></span>
53 % if c.commit.branch:
53 % if c.commit.branch:
54 <span class="tag branchtag">
54 <span class="tag branchtag">
55 <i class="icon-branch"></i> ${c.commit.branch}
55 <i class="icon-branch"></i> ${c.commit.branch}
56 </span>
56 </span>
57 % endif
57 % endif
58 </div>
58 </div>
59
59
60 <% form_url = h.route_path('repo_files_upload_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path) %>
60 <% form_url = h.route_path('repo_files_upload_file', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path) %>
61 ##${h.secure_form(form_url, id='eform', enctype="multipart/form-data", request=request)}
61 ##${h.secure_form(form_url, id='eform', enctype="multipart/form-data", request=request)}
62 <div class="edit-file-fieldset">
62 <div class="edit-file-fieldset">
63 <div class="path-items">
63 <div class="path-items">
64 <ul>
64 <ul>
65 <li class="breadcrumb-path">
65 <li class="breadcrumb-path">
66 <div>
66 <div>
67 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
67 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path='')}"><i class="icon-home"></i></a> /
68 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path)}">${c.f_path}</a> ${('/' if c.f_path else '')}
68 <a href="${h.route_path('repo_files', repo_name=c.repo_name, commit_id=c.commit.raw_id, f_path=c.f_path)}">${c.f_path}</a> ${('/' if c.f_path else '')}
69 </div>
69 </div>
70 </li>
70 </li>
71 <li class="location-path">
71 <li class="location-path">
72
72
73 </li>
73 </li>
74 </ul>
74 </ul>
75 </div>
75 </div>
76
76
77 </div>
77 </div>
78
78
79 <div class="upload-form table">
79 <div class="upload-form table">
80 <div>
80 <div>
81
81
82 <div class="dropzone-wrapper" id="file-uploader">
82 <div class="dropzone-wrapper" id="file-uploader">
83 <div class="dropzone-pure">
83 <div class="dropzone-pure">
84 <div class="dz-message">
84 <div class="dz-message">
85 <i class="icon-upload" style="font-size:36px"></i></br>
85 <i class="icon-upload" style="font-size:36px"></i></br>
86 ${_("Drag'n Drop files here or")} <span class="link">${_('Choose your files')}</span>.<br>
86 ${_("Drag'n Drop files here or")} <span class="link">${_('Choose your files')}</span>.<br>
87 </div>
87 </div>
88 </div>
88 </div>
89
89
90 </div>
90 </div>
91 </div>
91 </div>
92
92
93 </div>
93 </div>
94
94
95 <div class="upload-form edit-file-fieldset">
95 <div class="upload-form edit-file-fieldset">
96 <div class="fieldset">
96 <div class="fieldset">
97 <div class="message">
97 <div class="message">
98 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
98 <textarea id="commit" name="message" placeholder="${c.default_message}"></textarea>
99 </div>
99 </div>
100 </div>
100 </div>
101 <div class="pull-left">
101 <div class="pull-left">
102 ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
102 ${h.submit('commit_btn',_('Commit changes'), class_="btn btn-small btn-success")}
103 </div>
103 </div>
104 </div>
104 </div>
105 ##${h.end_form()}
105 ##${h.end_form()}
106
106
107 <div class="file-upload-transaction-wrapper" style="display: none">
107 <div class="file-upload-transaction-wrapper" style="display: none">
108 <div class="file-upload-transaction">
108 <div class="file-upload-transaction">
109 <h3>${_('Commiting...')}</h3>
109 <h3>${_('Committing...')}</h3>
110 <p>${_('Please wait while the files are being uploaded')}</p>
110 <p>${_('Please wait while the files are being uploaded')}</p>
111 <p class="error" style="display: none">
111 <p class="error" style="display: none">
112
112
113 </p>
113 </p>
114 <i class="icon-spin animate-spin"></i>
114 <i class="icon-spin animate-spin"></i>
115 <p></p>
115 <p></p>
116 </div>
116 </div>
117 </div>
117 </div>
118
118
119 </div>
119 </div>
120
120
121 <script type="text/javascript">
121 <script type="text/javascript">
122
122
123 $(document).ready(function () {
123 $(document).ready(function () {
124
124
125 //see: https://www.dropzonejs.com/#configuration
125 //see: https://www.dropzonejs.com/#configuration
126 myDropzone = new Dropzone("div#file-uploader", {
126 myDropzone = new Dropzone("div#file-uploader", {
127 url: "${form_url}",
127 url: "${form_url}",
128 headers: {"X-CSRF-Token": CSRF_TOKEN},
128 headers: {"X-CSRF-Token": CSRF_TOKEN},
129 paramName: function () {
129 paramName: function () {
130 return "files_upload"
130 return "files_upload"
131 }, // The name that will be used to transfer the file
131 }, // The name that will be used to transfer the file
132 parallelUploads: 20,
132 parallelUploads: 20,
133 maxFiles: 20,
133 maxFiles: 20,
134 uploadMultiple: true,
134 uploadMultiple: true,
135 //chunking: true, // use chunking transfer, not supported at the moment
135 //chunking: true, // use chunking transfer, not supported at the moment
136 //maxFilesize: 2, // in MBs
136 //maxFilesize: 2, // in MBs
137 autoProcessQueue: false, // if false queue will not be processed automatically.
137 autoProcessQueue: false, // if false queue will not be processed automatically.
138 createImageThumbnails: false,
138 createImageThumbnails: false,
139 previewTemplate: document.querySelector('#tpl-dropzone').innerHTML,
139 previewTemplate: document.querySelector('#tpl-dropzone').innerHTML,
140 accept: function (file, done) {
140 accept: function (file, done) {
141 done();
141 done();
142 },
142 },
143 init: function () {
143 init: function () {
144 this.on("addedfile", function (file) {
144 this.on("addedfile", function (file) {
145
145
146 });
146 });
147
147
148 this.on("sending", function (file, xhr, formData) {
148 this.on("sending", function (file, xhr, formData) {
149 formData.append("message", $('#commit').val());
149 formData.append("message", $('#commit').val());
150 $(file.previewElement).find('.dz-sending').show();
150 $(file.previewElement).find('.dz-sending').show();
151 });
151 });
152
152
153 this.on("success", function (file, response) {
153 this.on("success", function (file, response) {
154 $(file.previewElement).find('.dz-sending').hide();
154 $(file.previewElement).find('.dz-sending').hide();
155 $(file.previewElement).find('.dz-response').show();
155 $(file.previewElement).find('.dz-response').show();
156
156
157 if (response.error !== null) {
157 if (response.error !== null) {
158 $('.file-upload-transaction-wrapper .error').html('ERROR: {0}'.format(response.error));
158 $('.file-upload-transaction-wrapper .error').html('ERROR: {0}'.format(response.error));
159 $('.file-upload-transaction-wrapper .error').show();
159 $('.file-upload-transaction-wrapper .error').show();
160 $('.file-upload-transaction-wrapper i').hide()
160 $('.file-upload-transaction-wrapper i').hide()
161 }
161 }
162
162
163 var redirect_url = response.redirect_url || '/';
163 var redirect_url = response.redirect_url || '/';
164 window.location = redirect_url
164 window.location = redirect_url
165
165
166 });
166 });
167
167
168 this.on("error", function (file, errorMessage, xhr) {
168 this.on("error", function (file, errorMessage, xhr) {
169 var error = null;
169 var error = null;
170
170
171 if (xhr !== undefined){
171 if (xhr !== undefined){
172 var httpStatus = xhr.status + " " + xhr.statusText;
172 var httpStatus = xhr.status + " " + xhr.statusText;
173 if (xhr !== undefined && xhr.status >= 500) {
173 if (xhr !== undefined && xhr.status >= 500) {
174 error = httpStatus;
174 error = httpStatus;
175 }
175 }
176 }
176 }
177
177
178 if (error === null) {
178 if (error === null) {
179 error = errorMessage.error || errorMessage || httpStatus;
179 error = errorMessage.error || errorMessage || httpStatus;
180 }
180 }
181
181
182 $(file.previewElement).find('.dz-error-message').html('ERROR: {0}'.format(error));
182 $(file.previewElement).find('.dz-error-message').html('ERROR: {0}'.format(error));
183 });
183 });
184 }
184 }
185 });
185 });
186
186
187 $('#commit_btn').on('click', function(e) {
187 $('#commit_btn').on('click', function(e) {
188 e.preventDefault();
188 e.preventDefault();
189 var button = $(this);
189 var button = $(this);
190 if (button.hasClass('clicked')) {
190 if (button.hasClass('clicked')) {
191 button.attr('disabled', true);
191 button.attr('disabled', true);
192 } else {
192 } else {
193 button.addClass('clicked');
193 button.addClass('clicked');
194 }
194 }
195
195
196 var files = myDropzone.getQueuedFiles();
196 var files = myDropzone.getQueuedFiles();
197 if (files.length === 0) {
197 if (files.length === 0) {
198 alert("Missing files");
198 alert("Missing files");
199 e.preventDefault();
199 e.preventDefault();
200 }
200 }
201
201
202 $('.upload-form').hide();
202 $('.upload-form').hide();
203 $('.file-upload-transaction-wrapper').show();
203 $('.file-upload-transaction-wrapper').show();
204 myDropzone.processQueue();
204 myDropzone.processQueue();
205
205
206 });
206 });
207
207
208 });
208 });
209
209
210 </script>
210 </script>
211 </%def>
211 </%def>
General Comments 0
You need to be logged in to leave comments. Login now