repo_master.html 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. {% extends "master.html" %}
  2. {% from "_projectstring.html" import projectstring, projecticon %}
  3. {% macro print_ssh_url(repo, end_url_ssh, current_user) %}
  4. {% if not (current_user |user_can_clone_ssh) %}
  5. <a href="{{ url_for('ui_ns.user_settings') + '#nav-ssh-tab' }}">
  6. You need to upload SSH key to be able to clone over SSH
  7. </a>
  8. {% elif not (current_user | user_group_can_ssh_commit) %}
  9. Only members of the {{ config["SSH_ACCESS_GROUPS"] | join(", ") }} group(s) can clone via ssh
  10. {% else %}
  11. <div class="form-group">
  12. <div class="input-group input-group-sm">
  13. <div class="input-group-prepend"><span class="input-group-text">SSH</span></div>
  14. <input class="form-control bg-white select-on-focus" type="text" value="{{
  15. end_url_ssh | git_url_ssh }}{{ repo.fullname }}.git" readonly>
  16. </div>
  17. </div>
  18. {% endif %}
  19. {% endmacro %}
  20. {% block title %}{{
  21. repo.namespace + '/' if repo.namespace }}{{ repo.name }}{% endblock %}
  22. {% set tag = "home" %}
  23. {% block content %}
  24. <div class="bg-light border border-bottom pt-3">
  25. <div class="container">
  26. <div class="row mb-3">
  27. <div class="col-6">
  28. <div class="row">
  29. <div class="col-auto pr-0">
  30. <h3>
  31. {% if repo.is_fork -%}
  32. <i class="fa fa-code-fork text-muted"></i>
  33. {% elif repo.mirrored_from -%}
  34. <i class="fa fa-cloud-download text-muted" title="Mirrored from {{
  35. repo.mirrored_from }}"></i>
  36. {%- else -%}
  37. <i class="fa {{projecticon()}} text-muted"></i>
  38. {%- endif -%}
  39. </h3>
  40. </div>
  41. <div class="col-auto pl-2">
  42. <h3 class="mb-0">
  43. {% if repo.is_fork -%}
  44. <a href="{{ url_for(
  45. 'ui_ns.view_user', username=repo.user.user)
  46. }}">{{ repo.user.user }}</a><span class="mt-1 text-muted">&nbsp;/&nbsp;</span>
  47. {%- endif -%}
  48. {%- if repo.namespace -%}
  49. <a href="{{ url_for(
  50. 'ui_ns.view_projects', namespace=repo.namespace, pattern='*')
  51. }}">{{ repo.namespace }}</a>&nbsp;/&nbsp;
  52. {%- endif -%}<a href="{{ url_for('ui_ns.view_repo',
  53. repo=repo.name,
  54. username=username,
  55. namespace=repo.namespace)
  56. }}"><strong>{{ repo.name }}</strong></a>
  57. {% if repo.private %}
  58. <span class="fa fa-lock text-danger fa-fw" title="Private project"></span>
  59. {% endif %}
  60. </h3>
  61. {% if repo.is_fork and repo.parent %}
  62. <span class="text-muted">
  63. Forked from
  64. <a href="{{ url_for(
  65. 'ui_ns.view_repo',
  66. repo=repo.parent.name,
  67. username=repo.parent.user.user if repo.parent.is_fork else None,
  68. namespace=repo.parent.namespace)}}">
  69. {{ repo.parent.fullname }}
  70. </a>
  71. {{repo.date_created|humanize_tooltip | safe}}
  72. </span>
  73. {% elif repo.is_fork and not repo.parent %}
  74. <span class="text-muted">
  75. Forked from a deleted repository {{repo.date_created|humanize_tooltip | safe}}
  76. </span>
  77. {% endif %}
  78. </div>
  79. </div>
  80. </div>
  81. <div class="col-6 text-right">
  82. <div class="btn-group">
  83. {% if g.authenticated %}
  84. {% if g.issues_enabled
  85. and not repo.settings.get('issue_tracker_read_only', False) %}
  86. <a href="{{ url_for('ui_ns.new_issue',
  87. repo=g.repo.name,
  88. username=g.repo.user.user if g.repo.is_fork else none,
  89. namespace=g.repo.namespace) }}"
  90. class="btn btn-outline-primary btn-sm">
  91. <i class="fa fa-exclamation-circle fa-fw"></i> New issue</a>
  92. {% endif %}
  93. {% if g.authenticated %}
  94. <div class="btn-group">
  95. <a class="btn btn-outline-primary btn-sm dropdown-toggle pointer"
  96. data-toggle="dropdown"
  97. aria-haspopup="true" aria-expanded="false" id="pr-button">
  98. <i class="fa fa-arrow-circle-down fa-fw"></i> Open PR
  99. </a>
  100. <div class="dropdown-menu dropdown-menu-right pointer" id="PR-dropdown">
  101. {% if g.repo_forked %}
  102. <span id="pr-dropdown-forklist">
  103. <div class="dropdown-header font-size-1">
  104. From <span><i class="fa fa-code-fork fa-fw"></i><strong>{{ g.fas_user.username }}</strong> / {{ repo.name }}</span>
  105. </div>
  106. <div class="dropdown-item pr-dropdown-spinner"><i class="fa fa-circle-o-notch fa-spin fa-1x fa-fw"></i></div>
  107. </span>
  108. <div class="dropdown-divider"></div>
  109. {% endif %}
  110. <span id="pr-dropdown-mainlist">
  111. <div class="dropdown-header font-size-1">
  112. From <span><i class="fa fa-calendar-o fa-rotate-270 fa-fw"></i><strong>{{ repo.name }}</strong></span>
  113. </div>
  114. <div class="dropdown-item pr-dropdown-spinner"><i class="fa fa-circle-o-notch fa-spin fa-1x fa-fw"></i></div>
  115. </span>
  116. <div class="dropdown-divider"></div>
  117. <a class="dropdown-item"
  118. href="{{ url_for('ui_ns.new_request_pull',
  119. repo=repo.name,
  120. username=username,
  121. namespace=repo.namespace,
  122. branch_to=head or 'master',
  123. branch_from=branchname or 'master') }}">
  124. New Pull Request
  125. </a>
  126. {% if not config.get('DISABLE_REMOTE_PR', True) %}
  127. <a class="dropdown-item"
  128. href="{{ url_for(
  129. 'ui_ns.new_remote_request_pull',
  130. repo=repo.name,
  131. username=username,
  132. namespace=repo.namespace) }}">
  133. New Remote Pull Request
  134. </a>
  135. {% endif %}
  136. </div>
  137. </div>
  138. {%endif%}
  139. <div class="btn-group">
  140. {% if g.repo_forked %}
  141. {% if g.fas_user.username == username %}
  142. <a href="{{ url_for(
  143. 'ui_ns.view_repo',
  144. repo=repo.name,
  145. namespace=repo.namespace) }}" class="btn btn-sm btn-outline-primary">
  146. <i class="fa fa-code-fork fa-fw"></i> View Upstream
  147. </a>
  148. {% else %}
  149. <a href="{{ url_for(
  150. 'ui_ns.view_repo',
  151. repo=repo.name,
  152. username=g.fas_user.username,
  153. namespace=repo.namespace) }}" class="btn btn-sm btn-outline-primary">
  154. <i class="fa fa-code-fork fa-fw"></i> View fork
  155. </a>
  156. {% endif %}
  157. {% else %}
  158. <form method="POST" name="fork_project" id="fork_project"
  159. action="{{ url_for(
  160. 'ui_ns.fork_project',
  161. repo=repo.name,
  162. username=username,
  163. namespace=repo.namespace) }}">
  164. {{ g.forkbuttonform.csrf_token }}
  165. </form>
  166. <button class="btn btn-sm btn-outline-primary fork_project_btn">
  167. <i class="fa fa-code-fork fa-fw"></i> Fork</button>
  168. {% endif %}
  169. </div>
  170. {% endif %}
  171. <div class="btn-group">
  172. <a href="#"
  173. class="btn btn-sm dropdown-toggle btn-outline-primary"
  174. data-toggle="dropdown" id="watch-button">
  175. <i class="fa fa-clone fa-fw"></i>
  176. <span>Clone</span>
  177. </a>
  178. <div class="dropdown-menu dropdown-menu-right">
  179. <div class="m-3" id="source-dropdown">
  180. <div>
  181. <h5><strong>Source Code</strong></h5>
  182. {% if g.authenticated and g.repo_committer %}
  183. {{ print_ssh_url(repo, "", g.fas_user.username) }}
  184. {% endif %}
  185. <div class="form-group">
  186. <div class="input-group input-group-sm">
  187. <div class="input-group-prepend"><span class="input-group-text">GIT</span></div>
  188. <input class="form-control bg-white select-on-focus" type="text" value="{{
  189. config.get('GIT_URL_GIT') }}{{ repo.path }}" readonly>
  190. </div>
  191. </div>
  192. {% if (config['DOC_APP_URL']
  193. and repo
  194. and repo.settings.get('project_documentation', True)
  195. )
  196. or
  197. (g.authenticated and g.repo_committer) %}
  198. <div id="giturl-more" class="hidden">
  199. {% if config['DOC_APP_URL']
  200. and repo
  201. and repo.settings.get('project_documentation', True) %}
  202. <h5><strong>Documentation</strong></h5>
  203. {% if g.authenticated and g.repo_committer %}
  204. {{ print_ssh_url(repo, "docs/", g.fas_user.username) }}
  205. {% endif %}
  206. <div class="form-group">
  207. <div class="input-group input-group-sm">
  208. <div class="input-group-prepend"><span class="input-group-text">GIT</span></div>
  209. <input class="form-control bg-white select-on-focus" type="text" value="{{
  210. config.get('GIT_URL_GIT') }}docs/{{ repo.path }}" readonly>
  211. </div>
  212. </div>
  213. {% endif %}
  214. {% if g.authenticated and g.repo_committer %}
  215. {% if g.issues_enabled %}
  216. <h5><strong>Issues</strong></h5>
  217. {{ print_ssh_url(repo, "tickets/", g.fas_user.username) }}
  218. {% endif %}
  219. <h5><strong>Pull Requests</strong></h5>
  220. {{ print_ssh_url(repo, "requests/", g.fas_user.username) }}
  221. {% endif %}
  222. <hr />
  223. <p>
  224. <a href="https://docs.pagure.org/pagure/usage/" target="_blank" rel="noopener noreferrer">
  225. Learn more about these different git repos.
  226. </a>
  227. </p>
  228. </div>
  229. <p class="text-right">
  230. <a id="giturl-toggle" class="pointer">
  231. Other Git URLs <i class="fa fa-angle-down" aria-hidden="true"></i>
  232. </a>
  233. </p>
  234. {% endif %}
  235. </div>
  236. </div>
  237. </div>
  238. </div>
  239. </div>
  240. </div>
  241. </div>
  242. {% include 'repo_master_navbar.html' %}
  243. </div>
  244. </div>
  245. <div class="container pt-5 repo-body-container">
  246. {% if g.authenticated and repo.settings.get('pull_request_access_only') %}
  247. <div class="container pt-2">
  248. <div class="alert alert-info alert-dismissible" role="alert">
  249. <button type="button" class="close" data-dismiss="info" aria-label="Close">
  250. <span aria-hidden="true">&times;</span>
  251. <span class="sr-only">Close</span>
  252. </button>
  253. <span class="oi blue-icon" data-glyph="file" title="PR Only"></span>
  254. This project does not support direct push to its git repo, all changes
  255. must be done via pull-requests from forks.
  256. </div>
  257. </div>
  258. {% endif %}
  259. {% block repo %}
  260. {% endblock %}
  261. </div>
  262. {% block widerepo %}
  263. {% endblock %}
  264. {% endblock %}
  265. {% block jscripts %}
  266. {{ super() }}
  267. <script type="text/javascript" nonce="{{ g.nonce }}" src="{{
  268. url_for('static', filename='vendor/lazyload/lazyload.min.js') }}?version={{ g.version}}"></script>
  269. <script type="text/javascript" nonce="{{ g.nonce }}">
  270. window.addEventListener("load", function(event) {
  271. lazyload();
  272. });
  273. </script>
  274. <script type="text/javascript" nonce="{{ g.nonce }}">
  275. $("#giturl-toggle").on('click', function(event){
  276. event.stopPropagation();
  277. $("#giturl-more").toggle();
  278. $("#giturl-toggle").hide();
  279. })
  280. $(".fork_project_btn").click(function() {
  281. $('#fork_project').submit();
  282. });
  283. $(".select-on-focus").on("focus", function() {
  284. $(this).select();
  285. });
  286. {% if g.authenticated and not g.repo_obj.is_empty %}
  287. {% if g.repo_committer or g.repo_forked %}
  288. var _cnt = 0;
  289. function process_task_results(_data, callback) {
  290. var _url = '{{ url_for("internal_ns.task_info", taskid='') }}' + _data.task;
  291. $.ajax({
  292. url: _url ,
  293. type: 'GET',
  294. data: {
  295. js: 1,
  296. count: _cnt,
  297. },
  298. dataType: 'JSON',
  299. success: function(res) {
  300. callback(res.results);
  301. $("#spinnergif").hide();
  302. },
  303. error: function(res) {
  304. _cnt += 1;
  305. if (_cnt < 600) {
  306. window.setTimeout(process_task_results, 1000, _data, callback);
  307. }
  308. }
  309. });
  310. }
  311. function generate_branch_list(data) {
  312. var _b = $("#pr-dropdown-mainlist");
  313. for (branch in data.new_branch){
  314. var url = "{{ url_for(
  315. 'ui_ns.new_request_pull',
  316. repo=repo.name,
  317. username=None,
  318. namespace=repo.namespace,
  319. branch_to='-',
  320. branch_from='-') }}";
  321. url = url.slice(0, -4) + data.new_branch[branch]['target_branch'] + '..' + branch;
  322. html = '<a class="dropdown-item " href="' + url + '">'
  323. + '<span class="badge badge-secondary border border-secondary badge-pill font-size-1">'
  324. + '<span class="fa fa-random fa-fw"> </span> '
  325. + branch
  326. + '</span></a> ';
  327. _b.append(html);
  328. }
  329. _b.show();
  330. $("#pr-dropdown-mainlist .pr-dropdown-spinner").hide();
  331. }
  332. function generate_branch_list_fork(data) {
  333. var _b = $("#pr-dropdown-forklist");
  334. for (branch in data.new_branch){
  335. var url = "{{ url_for(
  336. 'ui_ns.new_request_pull',
  337. repo=repo.name,
  338. username=g.fas_user.username,
  339. namespace=repo.namespace,
  340. branch_to='-',
  341. branch_from='-') }}";
  342. url = url.slice(0, -4) + data.new_branch[branch]['target_branch'] + '..' + branch;
  343. html = '<a class="dropdown-item " href="' + url + '">'
  344. + '<span class="badge badge-secondary border border-secondary badge-pill font-size-1">'
  345. + '<span class="fa fa-random fa-fw"> </span> '
  346. + branch
  347. + '</span></a> ';
  348. _b.append(html);
  349. }
  350. _b.show();
  351. $("#pr-dropdown-forklist .pr-dropdown-spinner").hide();
  352. }
  353. {% endif %}
  354. $("#pr-button").one("click",
  355. function() {
  356. var _pr_url = "{{ url_for('internal_ns.get_pull_request_ready_branch') }}";
  357. {% if g.repo_committer %}
  358. var data = {
  359. repo: "{{ repo.name }}",
  360. namespace: "{{ repo.namespace if repo.namespace }}",
  361. repouser: "",
  362. csrf_token: "{{ g.confirmationform.csrf_token.current_token }}",
  363. };
  364. $.post(_pr_url, data, null, dataType='json').done(
  365. function(data) {
  366. process_task_results(data, generate_branch_list);
  367. }).fail(
  368. function(data) {
  369. var _b = $("#pr-dropdown-mainlist");
  370. html = '<span class="badge-pill font-size-1">'
  371. + '<span class="fa fa-ban fa-fw"> </span> '
  372. + data.responseJSON.message
  373. + '</span>';
  374. _b.append(html);
  375. _b.show();
  376. $("#pr-dropdown-mainlist .pr-dropdown-spinner").hide();
  377. })
  378. {% else %}
  379. $("#pr-dropdown-mainlist .pr-dropdown-spinner").hide();
  380. {% endif %}
  381. var data = {
  382. repo: "{{ repo.name }}",
  383. namespace: "{{ repo.namespace if repo.namespace }}",
  384. repouser: "{{ g.fas_user.username }}",
  385. csrf_token: "{{ g.confirmationform.csrf_token.current_token }}",
  386. };
  387. $.post(_pr_url, data, null, dataType='json').done(
  388. function(data) {
  389. process_task_results(data, generate_branch_list_fork);
  390. }).fail(
  391. function(data) {
  392. var _b = $("#pr-dropdown-forklist");
  393. html = '<span class="badge-pill font-size-1">'
  394. + '<span class="fa fa-ban fa-fw"> </span> '
  395. + data.responseJSON.message
  396. + '</span>';
  397. _b.append(html);
  398. _b.show();
  399. $("#pr-dropdown-forklist .pr-dropdown-spinner").hide();
  400. })
  401. }
  402. );
  403. $('.pr_comment_form').submit(function() {
  404. return try_async_comment($(this), null);
  405. });
  406. {% endif %}
  407. </script>
  408. {% endblock %}
  409. {% block overviewtabs %}
  410. {% include 'repo_master_sidebar.html' %}
  411. {% endblock %}