settings.html 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479
  1. {% extends "repo_master.html" %}
  2. {% block title %}{{ select.capitalize() }} - {{
  3. repo.namespace + '/' if repo.namespace }}{{ repo.name }}{% endblock %}
  4. {% set tag = "home" %}
  5. {% block header %}
  6. <link href="{{ url_for('static', filename='vendor/selectize/selectize.bootstrap3.css') }}"
  7. rel="stylesheet" />
  8. {% endblock %}
  9. {% block repo %}
  10. <div class="container p-t-3">
  11. <div class="row">
  12. <div class="col">
  13. <nav>
  14. <div class="nav nav-tabs nav-sidetabs flex-column" id="nav-tab" role="tablist">
  15. <h5 class="pl-2 font-weight-bold text-muted">Project Settings</h5>
  16. <a class="nav-item nav-link active" id="projectdetails-tab" data-toggle="tab"
  17. href="#projectdetails" role="tab" aria-controls="projectdetails" aria-selected="true">Project Details</a>
  18. <a class="nav-item nav-link" id="defaultbranch-tab" data-toggle="tab"
  19. href="#defaultbranch" role="tab" aria-controls="defaultbranch">Default Branch</a>
  20. {% if config.get('WEBHOOK', False) %}
  21. <a class="nav-item nav-link" id="privatewebhookkey-tab" data-toggle="tab"
  22. href="#privatewebhookkey" role="tab" aria-controls="privatewebhookkey">Private Web Hook Key</a>
  23. {% endif %}
  24. <a class="nav-item nav-link" id="apikeys-tab" data-toggle="tab"
  25. href="#apikeys" role="tab" aria-controls="apikeys">API Keys</a>
  26. <a class="nav-item nav-link" id="projectoptions-tab" data-toggle="tab"
  27. href="#projectoptions" role="tab" aria-controls="projectoptions">Project Options</a>
  28. <a class="nav-item nav-link" id="publicnotifications-tab" data-toggle="tab"
  29. href="#publicnotifications" role="tab" aria-controls="publicnotifications">Public Notifications</a>
  30. {% if config.get('ENABLE_USER_MNGT', True) %}
  31. <a class="nav-item nav-link" id="usersgroups-tab" data-toggle="tab"
  32. href="#usersgroups" role="tab" aria-controls="usersgroups">Users &amp; Groups</a>
  33. {% endif %}
  34. {% if config.get('DEPLOY_KEY', True) %}
  35. <a class="nav-item nav-link" id="deploykey-tab" data-toggle="tab"
  36. href="#deploykey" role="tab" aria-controls="deploykey">Deploy Keys</a>
  37. {% endif %}
  38. {% if plugins %}
  39. <a class="nav-item nav-link" id="hooks-tab" data-toggle="tab"
  40. href="#hooks" role="tab" aria-controls="hooks">Hooks</a>
  41. {% endif %}
  42. {% if config.get('ENABLE_TICKETS', True)
  43. and repo.settings.get('issue_tracker', True) %}
  44. <a class="nav-item nav-link" id="priorities-tab" data-toggle="tab"
  45. href="#priorities" role="tab" aria-controls="priorities">Priorities</a>
  46. <a class="nav-item nav-link" id="roadmap-tab" data-toggle="tab"
  47. href="#roadmap" role="tab" aria-controls="roadmap">Roadmap</a>
  48. <a class="nav-item nav-link" id="closestatus-tab" data-toggle="tab"
  49. href="#closestatus" role="tab" aria-controls="closestatus">Close Status</a>
  50. <a class="nav-item nav-link" id="customfields-tab" data-toggle="tab"
  51. href="#customfields" role="tab" aria-controls="customfields">Custom Issue Fields</a>
  52. <a class="nav-item nav-link" id="reports-tab" data-toggle="tab"
  53. href="#reports" role="tab" aria-controls="reports">Reports</a>
  54. {% endif %}
  55. {% if (config.get('ENABLE_TICKETS', True)
  56. and repo.settings.get('issue_tracker', True))
  57. or repo.settings.get('pull_requests', True) %}
  58. <a class="nav-item nav-link" id="projecttags-tab" data-toggle="tab"
  59. href="#projecttags" role="tab" aria-controls="projecttags">Tags</a>
  60. <a class="nav-item nav-link" id="quickreplies-tab" data-toggle="tab"
  61. href="#quickreplies" role="tab" aria-controls="quickreplies">Quick Replies</a>
  62. {% endif %}
  63. <a class="nav-item nav-link" id="regen-tab" data-toggle="tab"
  64. href="#regen" role="tab" aria-controls="regen">Regenerate Repos</a>
  65. {% if config.get('ENABLE_GIVE_PROJECTS', True)
  66. and (repo.user.user == g.fas_user.username or pagure_admin)
  67. and not repo.is_fork %}
  68. <a class="nav-item nav-link" id="giveproject-tab" data-toggle="tab"
  69. href="#giveproject" role="tab" aria-controls="giveproject">Give Project</a>
  70. {% endif %}
  71. <a class="nav-item nav-link" id="repospanner-tab" data-toggle="tab"
  72. href="#repospanner" role="tab" aria-controls="repospanner">repoSpanner state</a>
  73. {% if (not repo.is_fork and config.get('ENABLE_DEL_PROJECTS', True))
  74. or
  75. (repo.is_fork and config.get('ENABLE_DEL_FORKS',
  76. config.get('ENABLE_DEL_PROJECTS', True))) %}
  77. <a class="nav-item nav-link" id="deleteproject-tab" data-toggle="tab"
  78. href="#deleteproject" role="tab" aria-controls="deleteproject">Delete Project</a>
  79. {% endif %}
  80. </div>
  81. </nav>
  82. </div>
  83. <div class="col-9">
  84. <div class="tab-content mt-4" id="nav-tabContent">
  85. <div class="tab-pane fade active show" id="projectdetails" role="tabpanel" aria-labelledby="projectdetails-tab">
  86. <h3 class="font-weight-bold mb-3">
  87. Project Details
  88. </h3>
  89. <div class="row">
  90. <div class="col">
  91. <form action="{{ url_for('ui_ns.update_project',
  92. repo=repo.name,
  93. username=username,
  94. namespace=repo.namespace) }}" method="post">
  95. <fieldset class="form-group">
  96. <label for="description">Description</label>
  97. <input class="form-control" name="description" value="{{
  98. repo.description if repo.description }}" required/>
  99. <small class="text-muted">Short description of the project</small>
  100. </fieldset>
  101. <fieldset class="form-group">
  102. <label for="url">Project's url</label>
  103. <input class="form-control" name="url" value="{{ repo.url if repo.url else '' }}" />
  104. <small class="text-muted">Website URL of the project</small>
  105. </fieldset>
  106. <fieldset class="form-group">
  107. <label for="avatar">Avatar email</label>
  108. <input class="form-control" name="avatar_email" value="{{ repo.avatar_email if repo.avatar_email else '' }}" />
  109. <small class="text-muted">Email address linked to avatar to display for the project</small>
  110. </fieldset>
  111. <fieldset class="form-group">
  112. <label for="tags">Project tags</label>
  113. <input class="form-control" name="tags" value="{{ repo.tags_text |join(', ') if repo.tags else '' }}" />
  114. <small class="text-muted">
  115. Tags for project itself, as a comma-separated list. Tags
  116. for issues are managed further down on this page.
  117. </small>
  118. </fieldset>
  119. {% if config.get('PRIVATE_PROJECTS', False) and repo.private %}
  120. <fieldset class="form-group">
  121. <label class="c-input c-checkbox">Private</label>
  122. <input type="checkbox" value="private" name="private" checked="" />
  123. <span class="c-indicator"></span>
  124. </fieldset>
  125. {% endif %}
  126. <button class="btn btn-primary" type="submit" title="Update description">
  127. Update
  128. </button>
  129. {{ form.csrf_token }}
  130. </form>
  131. </div>
  132. </div>
  133. </div>
  134. <div class="tab-pane fade" id="defaultbranch" role="tabpanel" aria-labelledby="defaultbranch-tab">
  135. <h3 class="font-weight-bold mb-3">
  136. Default Branch
  137. </h3>
  138. <div class="row">
  139. <div class="col">
  140. <form action="{{ url_for('ui_ns.change_ref_head',
  141. repo=repo.name,
  142. username=username,
  143. namespace=repo.namespace) }}" method="post">
  144. {{ branches_form.csrf_token }}
  145. {{ branches_form.branches(class_="c-select") }}
  146. <input class="btn btn-primary" type="submit" value="Make Default"/>
  147. </form>
  148. </div>
  149. </div>
  150. </div>
  151. {% if config.get('WEBHOOK', False) %}
  152. <div class="tab-pane fade" id="privatewebhookkey" role="tabpanel" aria-labelledby="privatewebhookkey-tab">
  153. <h3 class="font-weight-bold mb-3">
  154. Private web-hook key
  155. </h3>
  156. <div class="row">
  157. <div class="col">
  158. <p>
  159. Each message sent to the web-hook are signed via hmac and SHA1 using
  160. this private key.
  161. </p>
  162. <p>
  163. This key is private to your project, make sure to store in a safe place
  164. and do not share it.
  165. </p>
  166. <div class="form-group">
  167. <div class="input-group">
  168. <div class="input-group-prepend"><span class="input-group-text"><span class="fa fa-key"></span></span></div>
  169. <input class="form-control" type="text" value="{{ repo.hook_token }}" readonly>
  170. </div>
  171. </div>
  172. <form action="{{ url_for('ui_ns.new_repo_hook_token',
  173. repo=repo.name,
  174. username=username,
  175. namespace=repo.namespace) }}"
  176. method="post" class="icon">
  177. <button class="btn btn-primary" type="submit"
  178. onclick="return confirm('Are you sure to generate a new token for '
  179. + 'this project/fork? \nThis will break all web hook in place and '
  180. + 'cannot be un-done.');"
  181. title="Generate a new hook token">
  182. <span class="fa fa-refresh"></span> &nbsp;Re-generate
  183. </button>
  184. {{ form.csrf_token }}
  185. </form>
  186. </div>
  187. </div>
  188. </div>
  189. {% endif %}
  190. <div class="tab-pane fade" id="apikeys" role="tabpanel" aria-labelledby="apikeys-tab">
  191. <h3 class="font-weight-bold mb-3">
  192. API Keys
  193. <a href="{{ url_for(
  194. 'ui_ns.add_token',
  195. repo=repo.name,
  196. username=username,
  197. namespace=repo.namespace) }}" method="post" class="icon float-right">
  198. <button class="btn btn-sm btn-outline-primary" type="submit"
  199. title="Generate a new API token">
  200. Create new API Key
  201. </button>
  202. </a>
  203. </h3>
  204. <div class="row">
  205. <div class="col">
  206. <p>
  207. API keys are tokens used to authenticate you on pagure. They can also
  208. be used to grant access to 3rd party application to behave on this
  209. project on your name.
  210. </p>
  211. <p>
  212. These are your personal tokens; they are not visible to the other
  213. admins of this repository.
  214. </p>
  215. <p>
  216. These keys are valid for <span class="strong">60</span> days.
  217. </p>
  218. <p>
  219. These keys are private to your project, make sure to store in a safe
  220. place and do not share it.
  221. </p>
  222. {% if repo.tokens %}
  223. {% for token in repo.tokens %}
  224. {% if token.user.username == g.fas_user.username %}
  225. <div class="form-group">
  226. <div class="input-group">
  227. <div class="input-group-prepend">
  228. <span class="input-group-text">
  229. <span class="fa fa-key"></span>
  230. <strong> {{ token.description or '' }}</strong>
  231. </span>
  232. </div>
  233. <div class="input-group-prepend">
  234. <span class="input-group-text">
  235. <a href="#"
  236. data-toggle="modal" data-target="#acls{{ token.id }}">
  237. {{token.acls_list_pretty|length}} ACLs
  238. </a>
  239. </span>
  240. <div class="modal fade" id="acls{{ token.id }}" tabindex="-1"
  241. role="dialog" aria-labelledby="ACLs" aria-hidden="true">
  242. <div class="modal-dialog" role="document">
  243. <div class="modal-content">
  244. <div class="modal-header">
  245. <button type="button" class="close" data-dismiss="modal" aria-label="Close">
  246. <span aria-hidden="true">&times;</span>
  247. <span class="sr-only">Close</span>
  248. </button>
  249. <h4 class="modal-title" id="myModalLabel">ACLs</h4>
  250. </div>
  251. <div class="modal-body">
  252. <ul>
  253. {% for acl in token.acls_list_pretty %}
  254. <li>{{ acl }}</li>
  255. {% endfor %}
  256. </ul>
  257. </div>
  258. </div>
  259. </div>
  260. </div>
  261. </div>
  262. <input class="form-control bg-white" style="font-family:monospace" type="text" value="{{ token.id }}" readonly>
  263. {% if token.expired %}
  264. <span class="input-group-prepend">
  265. <span class="input-group-text text-danger">
  266. <small class="font-weight-bold">Expired on {{ token.expiration.date() }}</small>
  267. </span>
  268. </span>
  269. {% else %}
  270. <span class="input-group-prepend">
  271. <span class="input-group-text text-success">
  272. <small class="font-weight-bold">Active until {{ token.expiration.date() }}</small>
  273. </span>
  274. </span>
  275. {% endif %}
  276. {% if not token.expired %}
  277. <form action="{{ url_for(
  278. 'ui_ns.revoke_api_token',
  279. repo=repo.name,
  280. username=username,
  281. namespace=repo.namespace,
  282. token_id=token.id) }}"
  283. method="post" class="icon">
  284. <button class="btn btn-outline-danger" type="submit"
  285. onclick="return confirm('Are you sure to revoke this token ?'
  286. + '\nThis will break all application using it and '
  287. + 'cannot be un-done.');"
  288. title="Revoke token">
  289. <i class="fa fa-trash"></i>
  290. </button>
  291. {{ form.csrf_token }}
  292. </form>
  293. {% else %}
  294. <form action="{{ url_for(
  295. 'ui_ns.renew_api_token',
  296. repo=repo.name,
  297. username=username,
  298. namespace=repo.namespace,
  299. token_id=token.id) }}"
  300. method="post" class="icon">
  301. <button class="btn btn-outline-primary" type="submit"
  302. onclick="return confirm('Are you sure to renew this token ?'
  303. + '\nIt will have the same ACL but will be a different key.');"
  304. title="Renew token">
  305. <i class="fa fa-refresh"></i>
  306. </button>
  307. {{ form.csrf_token }}
  308. </form>
  309. {% endif %}
  310. </div>
  311. </div>
  312. {% endif %}
  313. {% endfor %}
  314. {% endif %}
  315. </div>
  316. </div>
  317. </div>
  318. <div class="tab-pane fade" id="projectoptions" role="tabpanel" aria-labelledby="projectoptions-tab">
  319. {% include 'settings_options.html' %}
  320. </div>
  321. <div class="tab-pane fade" id="publicnotifications" role="tabpanel" aria-labelledby="publicnotifications-tab">
  322. <h3 class="font-weight-bold mb-3">
  323. Public Notifications
  324. </h3>
  325. <div class="row">
  326. <div class="col">
  327. <p>
  328. The email addresses entered below will receive all the notifications
  329. related to {% if config.get('ENABLE_TICKETS', True) %}
  330. (public) issues and {% endif %}pull-requests, this includes
  331. notifications about {% if config.get('ENABLE_TICKETS', True) %}
  332. new issue or {% endif %} new pull-request, new comment
  333. and status change.
  334. </p>
  335. <p>
  336. To enter multiple addresses, separate them with a comma.
  337. </p>
  338. <form action="{{ url_for(
  339. 'ui_ns.update_public_notifications',
  340. repo=repo.name,
  341. username=username,
  342. namespace=repo.namespace) }}"
  343. method="post" class="icon">
  344. {{ tag_form.csrf_token }}
  345. <div class="card-body">
  346. {% if config.get('ENABLE_TICKETS', True) %}
  347. <div class="row">
  348. <div class="col-sm-12">
  349. <strong>Issues notifications</strong>
  350. </div>
  351. </div>
  352. <div id="issue-notifications">
  353. <div class="row p-t-1">
  354. <div class="col-sm-9 p-r-0">
  355. <input type="text" name="issue_notifs"
  356. value="{{ repo.notifications['issues'] | join(', ') }}" class="form-control"/>
  357. </div>
  358. </div>
  359. </div>
  360. {% endif %}
  361. <div class="row">
  362. <div class="col-sm-12 p-t-1">
  363. <strong>Pull-requests notifications</strong>
  364. </div>
  365. </div>
  366. <div id="pr-notifications">
  367. <div class="row p-t-1">
  368. <div class="col-sm-9 p-r-0">
  369. <input type="text" name="pr_notifs"
  370. value="{{ repo.notifications['requests'] | join(', ') }}" class="form-control"/>
  371. </div>
  372. </div>
  373. </div>
  374. <div class="row p-t-1">
  375. <div class="col-sm-12">
  376. <button class="btn btn-primary" type="submit"
  377. title="Update notifications">
  378. Update
  379. </button>
  380. </div>
  381. </div>
  382. </div>
  383. </form>
  384. </div>
  385. </div>
  386. </div>
  387. {% if config.get('ENABLE_USER_MNGT', True) %}
  388. <div class="tab-pane fade" id="usersgroups" role="tabpanel" aria-labelledby="usersgroups-tab">
  389. <h3 class="font-weight-bold mb-3">
  390. Users &amp; Groups
  391. </h3>
  392. <div class="row">
  393. <div class="col">
  394. <p>Below is the list of users having commit rights to this repo.</p>
  395. <p>
  396. <a href="{{ url_for(
  397. 'ui_ns.add_user',
  398. repo=repo.name,
  399. username=username,
  400. namespace=repo.namespace) }}"
  401. class="btn btn-primary">
  402. add user
  403. </a>
  404. <a href="{{ url_for(
  405. 'ui_ns.add_group_project',
  406. repo=repo.name,
  407. username=username,
  408. namespace=repo.namespace) }}"
  409. class="btn btn-primary">
  410. add group
  411. </a>
  412. </p>
  413. <ul class="list-group">
  414. <li class="list-group-item">
  415. <a href="{{ url_for('ui_ns.view_user', username=repo.user.user) }}">
  416. <span class="fa fa-user"></span>
  417. &nbsp; {{ repo.user.user }}
  418. </a>
  419. (main admin)
  420. </li>
  421. {% for access in access_users %}
  422. {% for user in access_users[access] %}
  423. <li class="list-group-item">
  424. <a href="{{ url_for('ui_ns.view_user', username=user.user) }}">
  425. <span class="fa fa-user"></span>
  426. &nbsp; {{ user.user }}
  427. </a>
  428. ({{access}})
  429. <form class="pull-xs-right" method="POST"
  430. action="{{ url_for(
  431. 'ui_ns.remove_user',
  432. repo=repo.name,
  433. username=username,
  434. namespace=repo.namespace,
  435. userid=user.id) }}">
  436. <button
  437. onclick="return confirm('You sure you want to remove this user from this project?');"
  438. title="Remove user" class="btn btn-danger btn-sm">
  439. <i class="fa fa-trash"></i>
  440. </button>
  441. {{ form.csrf_token }}
  442. </form>
  443. <a href="{{ url_for(
  444. 'ui_ns.add_user',
  445. repo=repo.name,
  446. username=username,
  447. namespace=repo.namespace)
  448. }}?user={{ user.user }}">
  449. <button title="Update User Access" class="btn btn-default btn-sm pull-xs-right">
  450. <i class="fa fa-pencil"></i>
  451. </button>
  452. </a>
  453. </li>
  454. {% endfor %}
  455. {% endfor %}
  456. {% for access in access_groups %}
  457. {% for group in access_groups[access] %}
  458. <li class="list-group-item">
  459. <a href="{{ url_for('ui_ns.view_group', group=group.group_name) }}">
  460. <span class="fa fa-users"></span>
  461. &nbsp; {{ group.group_name }}
  462. </a>
  463. ({{access}})
  464. <form class="pull-xs-right" method="POST"
  465. action="{{ url_for(
  466. 'ui_ns.remove_group_project',
  467. repo=repo.name,
  468. username=username,
  469. namespace=repo.namespace,
  470. groupid=group.id) }}">
  471. <button
  472. onclick="return confirm('You sure you want to remove this group from this project?');"
  473. title="Remove group" class="btn btn-danger btn-sm pull-xs-right">
  474. <i class="fa fa-trash"></i>
  475. </button>
  476. {{ form.csrf_token }}
  477. </form>
  478. <a href="{{ url_for(
  479. 'ui_ns.add_group_project',
  480. repo=repo.name,
  481. username=username,
  482. namespace=repo.namespace)
  483. }}?group={{ group.group_name }}">
  484. <button class="btn btn-default btn-sm pull-xs-right" title="Update Group Access" >
  485. <i class="fa fa-pencil"></i>
  486. </button>
  487. </a>
  488. </li>
  489. {% endfor %}
  490. {% endfor %}
  491. </ul>
  492. </div>
  493. </div>
  494. </div>
  495. {% endif %}
  496. {% if config.get('DEPLOY_KEY', True) %}
  497. <div class="tab-pane fade" id="deploykey" role="tabpanel" aria-labelledby="deploykey-tab">
  498. <h3 class="font-weight-bold mb-3">
  499. Deploy Keys
  500. <a href="{{ url_for(
  501. 'ui_ns.add_deploykey',
  502. repo=repo.name,
  503. username=username,
  504. namespace=repo.namespace) }}"
  505. class="btn btn-outline-primary btn-sm float-right">
  506. add deploy key
  507. </a>
  508. </h3>
  509. <div class="row">
  510. <div class="col">
  511. <p>Below are this projects' deploy keys.</p>
  512. {% for deploykey in repo.deploykeys %}
  513. <div class="form-group">
  514. <div class="input-group">
  515. <div class="input-group-prepend">
  516. <span class="input-group-text"><span class="fa fa-key"></span></span>
  517. </div>
  518. {% if deploykey.pushaccess %}
  519. <div class="input-group-prepend">
  520. <span class="input-group-text">Push Access</span>
  521. </div>
  522. {% endif %}
  523. <input class="form-control bg-white" style="font-family:monospace" readonly
  524. type="text" value="{{ deploykey.ssh_short_key }}"/>
  525. <form class="pull-xs-right" method="POST"
  526. action="{{ url_for(
  527. 'ui_ns.remove_deploykey',
  528. repo=repo.name,
  529. username=username,
  530. namespace=repo.namespace,
  531. keyid=deploykey.id) }}">
  532. <button
  533. onclick="return confirm('You sure you want to remove this deploy key from this project?');"
  534. title="Remove deploy key" class="btn btn-outline-danger">
  535. <i class="fa fa-trash"></i>
  536. </button>
  537. {{ form.csrf_token }}
  538. </form>
  539. </div>
  540. </div>
  541. {% endfor %}
  542. </div>
  543. </div>
  544. </div>
  545. {% endif %}
  546. {% if plugins %}
  547. <div class="tab-pane fade" id="hooks" role="tabpanel" aria-labelledby="hooks-tab">
  548. <h3 class="font-weight-bold mb-3">
  549. Hooks
  550. </h3>
  551. <div class="row">
  552. <div class="col">
  553. <div id="accordions" role="tablist" aria-multiselectable="true">
  554. {% for plugin in plugins %}
  555. {% if not config.get('ENABLE_TICKETS', True) and plugin in ['Pagure tickets'] %}
  556. {% else %}
  557. <div class="panel panel-default" >
  558. <div class="panel-heading" role="tab" id="pluginheading{{ loop.index }}">
  559. <h4 class="panel-title">
  560. <a data-toggle="collapse" data-parent="#accordions"
  561. href="#plugincollapse{{ loop.index }}" aria-expanded="true"
  562. aria-controls="plugincollapse{{ loop.index }}">
  563. <span id="dropdowncaret" class="fa fa-caret-right">
  564. </span>&nbsp;{{ plugin }}
  565. </a>
  566. </h4>
  567. </div>
  568. <div id="plugincollapse{{ loop.index }}" data-plugin="{{ plugin }}"
  569. class="panel-collapse collapse" role="tabpanel"
  570. aria-labelledby="pluginheading{{ loop.index }}">
  571. <span class="oi oi-spin pull-left" data-glyph="loop-circular">
  572. </span>
  573. </div>
  574. </div>
  575. {% endif %}
  576. {% endfor %}
  577. </div>
  578. </div>
  579. </div>
  580. </div>
  581. {% endif %}
  582. {% if config.get('ENABLE_TICKETS', True)
  583. and repo.settings.get('issue_tracker', True) %}
  584. <div class="tab-pane fade" id="priorities" role="tabpanel" aria-labelledby="priorities-tab">
  585. <h3 class="font-weight-bold mb-3">
  586. Priorities
  587. </h3>
  588. <div class="row">
  589. <div class="col">
  590. <p>
  591. Below are the priorities you may assign to a ticket, allowing you
  592. to sort them with it. The Weight determines the ordering. Higher
  593. priority should correspond to lower weight.
  594. <span class="italic">
  595. To remove an entry, simply clean the Weight and Title
  596. </span>
  597. </p>
  598. <form action="{{ url_for(
  599. 'ui_ns.update_priorities',
  600. repo=repo.name,
  601. username=username,
  602. namespace=repo.namespace) }}"
  603. method="post" class="icon">
  604. {{ tag_form.csrf_token }}
  605. <div class="row">
  606. <div class="col-sm-2">
  607. <strong>Weight</strong>
  608. </div>
  609. <div class="col-sm-10">
  610. <strong>Title</strong>
  611. </div>
  612. </div>
  613. <div class="form-group settings-field-rows" id="priorities-list">
  614. {% for priority in ((repo.priorities or [""]) | sort) %}
  615. <div class="row {{'hidden blank-field' if priority == ''}}">
  616. <div class="col-sm-2" >
  617. <input type="text" name="priority_weigth"
  618. value="{{ priority }}" size="3" class="form-control"/>
  619. </div>
  620. <div class="col-sm-9">
  621. <input type="text" name="priority_title"
  622. value="{{ repo.priorities[priority] }}" class="form-control"/>
  623. </div>
  624. <div class="col-sm-1">
  625. <a href="javascript:void(0)" class="btn btn-outline-danger remove-settings-field-row"><i class="fa fa-trash"></i></a>
  626. </div>
  627. </div>
  628. {% endfor %}
  629. </div>
  630. <a href="javascript:void(0)" class="btn btn-outline-primary pt-2 btn-sm btn-block add-settings-field-row" data-target="#priorities-list">
  631. <i class="fa fa-plus"></i> Add new priority
  632. </a>
  633. {% if not repo.priorities %}
  634. <a href="javascript:void(0)" class="btn btn-outline-secondary btn-sm btn-block" id="default_priorities">
  635. Populate with defaults
  636. </a>
  637. {% endif %}
  638. <div class="row p-t-1">
  639. </div>
  640. <div class="row p-t-1">
  641. <div class="col-sm-12">
  642. <button class="btn btn-primary float-right mt-3" type="submit"
  643. title="Update the priorities">
  644. Update
  645. </button>
  646. </div>
  647. </div>
  648. </form>
  649. </div>
  650. </div>
  651. {% if repo.priorities %}
  652. <h3 class="font-weight-bold mb-3">
  653. Default Priority
  654. </h3>
  655. <div class="row">
  656. <div class="col">
  657. <p>
  658. The default priority will be set to all issues created after
  659. it has been set.
  660. </p>
  661. <form action="{{ url_for(
  662. 'ui_ns.default_priority',
  663. repo=repo.name,
  664. username=username,
  665. namespace=repo.namespace) }}"
  666. method="post" class="icon">
  667. {{ tag_form.csrf_token }}
  668. <div class="card-body">
  669. <div class="row">
  670. <div class="col-sm-12">
  671. <strong>Default priority</strong>
  672. </div>
  673. </div>
  674. <div id="default_priority">
  675. {{ priority_form.priority(class_="c-select") }}
  676. </div>
  677. <div class="row p-t-1">
  678. <div class="col-sm-12">
  679. <button class="btn btn-primary" type="submit"
  680. title="Update the default priority">
  681. Update
  682. </button>
  683. </div>
  684. </div>
  685. </div>
  686. </form>
  687. </div>
  688. </div>
  689. {% endif %}
  690. </div>
  691. <div class="tab-pane fade" id="roadmap" role="tabpanel" aria-labelledby="roadmap-tab">
  692. {% include 'settings_milestones.html' %}
  693. </div>
  694. <div class="tab-pane fade" id="closestatus" role="tabpanel" aria-labelledby="closestatus-tab">
  695. <h3 class="font-weight-bold mb-3">
  696. Close Status
  697. </h3>
  698. <div class="row">
  699. <div class="col">
  700. <p>
  701. Here is the list of all the status that can be used when closing
  702. an issue.
  703. </p>
  704. <form action="{{ url_for(
  705. 'ui_ns.update_close_status',
  706. repo=repo.name,
  707. username=username,
  708. namespace=repo.namespace) }}"
  709. method="post" class="icon">
  710. {{ tag_form.csrf_token }}
  711. <div class="row">
  712. <div class="col-sm-12">
  713. <strong>Status</strong>
  714. </div>
  715. </div>
  716. <div class="form-group settings-field-rows" id="status-list">
  717. <div class="row hidden blank-field">
  718. <div class="col-sm-11" >
  719. <input type="text" name="close_status"
  720. value="" class="form-control"/>
  721. </div>
  722. <div class="col-sm-1">
  723. <a href="javascript:void(0)" class="btn btn-outline-danger remove-settings-field-row"><i class="fa fa-trash"></i></a>
  724. </div>
  725. </div>
  726. {% for status in repo.close_status | sort %}
  727. <div class="row {{'hidden blank-field' if status == ''}}">
  728. <div class="col-sm-11" >
  729. <input type="text" name="close_status"
  730. value="{{ status }}" class="form-control"/>
  731. </div>
  732. <div class="col-sm-1">
  733. <a href="javascript:void(0)" class="btn btn-outline-danger remove-settings-field-row"><i class="fa fa-trash"></i></a>
  734. </div>
  735. </div>
  736. {% endfor %}
  737. </div>
  738. <a href="javascript:void(0)" class="btn btn-outline-primary pt-2 btn-sm btn-block add-settings-field-row" data-target="#status-list">
  739. <i class="fa fa-plus"></i> Add new close status
  740. </a>
  741. {% if not repo.close_status %}
  742. <a href="javascript:void(0)" class="btn btn-outline-secondary btn-sm btn-block" id="default_statuses">
  743. Populate with defaults
  744. </a>
  745. {% endif %}
  746. <div class="row p-t-1">
  747. </div>
  748. <div class="row p-t-1">
  749. <div class="col-sm-12">
  750. <button class="btn btn-primary float-right mt-3" type="submit"
  751. title="Update the statuses">
  752. Update
  753. </button>
  754. </div>
  755. </div>
  756. </form>
  757. </div>
  758. </div>
  759. </div>
  760. <div class="tab-pane fade" id="customfields" role="tabpanel" aria-labelledby="customfields-tab">
  761. <h3 class="font-weight-bold mb-3">
  762. Custom Issue Fields
  763. </h3>
  764. <div class="row">
  765. <div class="col">
  766. <p>
  767. Set some custom fields for your issues. <i>Field Values</i> are currently
  768. only used for Lists, and it accepts a comma separated list of items
  769. for the drop down list.
  770. </p>
  771. <form action="{{ url_for(
  772. 'ui_ns.update_custom_keys',
  773. repo=repo.name,
  774. username=username,
  775. namespace=repo.namespace) }}"
  776. method="post" class="icon">
  777. {{ tag_form.csrf_token }}
  778. <div class="row">
  779. <div class="col-sm-2">
  780. <strong>Fields</strong>
  781. </div>
  782. <div class="col-sm-2">
  783. <strong>Field Type</strong>
  784. </div>
  785. <div class="col-sm-6">
  786. <strong>Field Values</strong> <i>(Lists only)</i>
  787. </div>
  788. <div class="col-sm-1">
  789. <strong>Notify</strong>
  790. </div>
  791. </div>
  792. <div class="form-group settings-field-rows" id="customfields-list">
  793. <div class="row hidden blank-field">
  794. <div class="col-sm-2 pr-0">
  795. <input type="text" name="custom_keys"
  796. value="" class="form-control"/>
  797. </div>
  798. <div class="col-sm-2 pr-0">
  799. <select name="custom_keys_type" class="form-control">
  800. <option value="text">Text</option>
  801. <option value="boolean">Boolean</option>
  802. <option value="link">Link</option>
  803. <option value="list">List</option>
  804. </select>
  805. </div>
  806. <div class="col-sm-6 pr-0">
  807. <input title="Comma separated list items" type="text" name="custom_keys_data"
  808. value="" class="form-control"/>
  809. </div>
  810. <div class="col-sm-1 pr-0">
  811. <input type="checkbox" name="custom_keys_notify" title="Trigger email notification when updated">
  812. </div>
  813. <div class="col-sm-1">
  814. <a href="javascript:void(0)" class="btn btn-outline-danger remove-settings-field-row"><i class="fa fa-trash"></i></a>
  815. </div>
  816. </div>
  817. {% for field in repo.issue_keys | sort %}
  818. <div class="row">
  819. <div class="col-sm-2 pr-0">
  820. <input type="text" name="custom_keys"
  821. value="{{ field.name }}" class="form-control"/>
  822. </div>
  823. <div class="col-sm-2 pr-0">
  824. <select name="custom_keys_type" class="form-control">
  825. <option value="text" {%
  826. if field.key_type == 'text' %} selected {%
  827. endif %}>Text</option>
  828. <option value="boolean" {%
  829. if field.key_type == 'boolean' %} selected {%
  830. endif %}>Boolean</option>
  831. <option value="link" {%
  832. if field.key_type == 'link' %} selected {%
  833. endif %}>Link</option>
  834. <option value="list" {%
  835. if field.key_type == 'list' %} selected {%
  836. endif %}>List</option>
  837. </select>
  838. </div>
  839. <div class="col-sm-6 pr-0">
  840. <input title="Comma separated list items" type="text" name="custom_keys_data"
  841. value={% if field.data is none %}""{% else %}"{{ field.data | join(', ') }}"{% endif %} class="form-control"/>
  842. </div>
  843. <div class="col-sm-1 pr-0">
  844. <input type="checkbox" name="custom_keys_notify-{{ loop.index }}" title="Trigger email notification when updated"
  845. {% if field.key_notify == True %}
  846. checked="y"
  847. {% endif %}
  848. class="form-control"/>
  849. </div>
  850. <div class="col-sm-1">
  851. <a href="javascript:void(0)" class="btn btn-outline-danger remove-settings-field-row"><i class="fa fa-trash"></i></a>
  852. </div>
  853. </div>
  854. {% endfor %}
  855. </div>
  856. <a href="javascript:void(0)" class="btn btn-outline-primary pt-2 btn-sm btn-block add-settings-field-row" data-target="#customfields-list">
  857. <i class="fa fa-plus"></i> Add new custom field
  858. </a>
  859. <button class="btn btn-primary mt-3 float-right" type="submit"
  860. title="Update the custom fields">
  861. Update
  862. </button>
  863. </form>
  864. </div>
  865. </div>
  866. </div>
  867. <div class="tab-pane fade" id="reports" role="tabpanel" aria-labelledby="reports-tab">
  868. <h3 class="font-weight-bold mb-3">
  869. Reports
  870. </h3>
  871. <div class="row">
  872. <div class="col">
  873. <p>
  874. Here is the list of reports saved for this project.
  875. </p>
  876. <ul class="list-group">
  877. {% for report in repo.reports %}
  878. <li class="list-group-item clearfix">
  879. <a href="{{ url_for(
  880. 'ui_ns.view_report',
  881. repo=repo.name,
  882. username=username,
  883. namespace=repo.namespace,
  884. report=report) }}">
  885. {{ report }}
  886. </a>
  887. <div class="float-right">
  888. <form class="icon del_icon float-right" method="POST"
  889. action="{{ url_for(
  890. 'ui_ns.delete_report',
  891. repo=repo.name,
  892. username=username,
  893. namespace=repo.namespace) }}">
  894. <input type="hidden" value="{{ report }}" name="report" />
  895. {{ tag_form.csrf_token }}
  896. <button
  897. onclick="return confirm('Do you really want to remove the report: {{ report }}?');"
  898. title="Delete report" class="btn btn-danger btn-sm">
  899. <i class="fa fa-trash"></i>
  900. </button>
  901. </form>
  902. </div>
  903. </li>
  904. {% endfor %}
  905. </ul>
  906. </div>
  907. </div>
  908. </div>
  909. {% endif %}
  910. {% if (config.get('ENABLE_TICKETS', True)
  911. and repo.settings.get('issue_tracker', True))
  912. or repo.settings.get('pull_requests', True) %}
  913. <div class="tab-pane fade" id="projecttags" role="tabpanel" aria-labelledby="projecttags-tab">
  914. <h3 class="font-weight-bold mb-3">
  915. Tags
  916. </h3>
  917. <div class="row">
  918. <div class="col">
  919. <p>
  920. Here is the list of tags associated with this project (Issues and Pull Requests).
  921. </p>
  922. <ul class="list-group">
  923. {% for tag in tags %}
  924. <li class="list-group-item clearfix">
  925. <a href="{{ url_for(
  926. 'ui_ns.view_issues',
  927. repo=repo.name,
  928. username=username,
  929. namespace=repo.namespace,
  930. tags=tag.tag) }}">
  931. <span class="fa fa-tag"></span>&nbsp; {{ tag.tag }}
  932. </a>
  933. &nbsp;<span class="badge badge-info" style="background-color:{{tag.tag_color}}">{{tag.tag}}</span>
  934. &nbsp;<span class="text-muted">{{ tag.tag_description or '' }}</span>
  935. <div class="float-right">
  936. <form class="icon del_icon float-right" method="POST"
  937. action="{{ url_for(
  938. 'ui_ns.remove_tag',
  939. repo=repo.name,
  940. username=username,
  941. namespace=repo.namespace) }}">
  942. <input type="hidden" value="{{ tag.tag }}" name="tag" />
  943. {{ tag_form.csrf_token }}
  944. <button
  945. onclick="return confirm('Do you really want to remove the tag: {{ tag.tag }}?');"
  946. title="Remove tag" class="btn btn-danger btn-sm">
  947. <i class="fa fa-trash"></i>
  948. </button>
  949. </form>
  950. <a href="{{ url_for(
  951. 'ui_ns.edit_tag',
  952. repo=repo.name,
  953. username=username,
  954. namespace=repo.namespace,
  955. tag=tag.tag) }}">
  956. <button class="btn btn-default btn-sm" title="Edit tag">
  957. <i class="fa fa-pencil"></i>
  958. </button>
  959. </a>
  960. </div>
  961. </li>
  962. {% endfor %}
  963. </ul>
  964. <form action="{{ url_for(
  965. 'ui_ns.update_tags',
  966. repo=repo.name,
  967. username=username,
  968. namespace=repo.namespace) }}"
  969. method="post" class="icon">
  970. {{ tag_form.csrf_token }}
  971. <div class="card-body">
  972. <!-- The "Add New Tag" rows/elements will fill in here -->
  973. <div id="tagcolor">
  974. </div>
  975. <div class="row p-t-1">
  976. <div class="col-sm-12">
  977. <a class="btn btn-outline-primary btn-sm btn-block" id="new_tag" href="javascript:void(0)">
  978. Add New Tag
  979. </a>
  980. </div>
  981. </div>
  982. <div class="row p-t-1">
  983. <div class="col-sm-12">
  984. <button class="btn btn-primary float-right mt-3" type="submit"
  985. title="Update the tags">
  986. Update
  987. </button>
  988. </div>
  989. </div>
  990. </div>
  991. </form>
  992. </div>
  993. </div>
  994. </div>
  995. <div class="tab-pane fade" id="quickreplies" role="tabpanel" aria-labelledby="quickreplies-tab">
  996. <h3 class="font-weight-bold mb-3">
  997. Quick Replies
  998. </h3>
  999. <div class="row">
  1000. <div class="col">
  1001. <p>Quick replies will be offered in a new comment form on Issue or
  1002. Pull Request page. This allows you to reply to common problems with a
  1003. click of a button.</p>
  1004. <p>The reply can use the same Markdown formatting as regular
  1005. comments. The list you will choose the reply from will only show the
  1006. first 50 characters. Please make sure the important message is at the
  1007. beginning.</p>
  1008. <p>The replies will be presented in the same order they are written
  1009. here.</p>
  1010. <form action="{{ url_for(
  1011. 'ui_ns.update_quick_replies',
  1012. repo=repo.name,
  1013. username=username,
  1014. namespace=repo.namespace) }}"
  1015. method="post">
  1016. {{ tag_form.csrf_token }}
  1017. <div class="card-body">
  1018. <div id="quick_reply_list">
  1019. {% for quick_reply in repo.quick_replies or [""] %}
  1020. <div class="row p-t-1">
  1021. <div class="col-sm-12 p-r-0">
  1022. <textarea class="form-control" name="quick_reply">{{quick_reply}}</textarea>
  1023. </div>
  1024. </div>
  1025. {% endfor %}
  1026. </div>
  1027. <div class="row p-t-1">
  1028. <div class="col-sm-6">
  1029. <a class="btn btn-secondary btn-sm btn-block extend-form" data-target="#quick_reply_list">
  1030. Add new quick reply
  1031. </a>
  1032. </div>
  1033. </div>
  1034. <div class="row p-t-1">
  1035. <div class="col-sm-12">
  1036. <button class="btn btn-primary" type="submit"
  1037. title="Update quick replies">
  1038. Update
  1039. </button>
  1040. </div>
  1041. </div>
  1042. </div>
  1043. </form>
  1044. </div>
  1045. </div>
  1046. </div>
  1047. {% endif %}
  1048. <div class="tab-pane fade" id="regen" role="tabpanel" aria-labelledby="regen-tab">
  1049. <h3 class="font-weight-bold mb-3">
  1050. Regenerate Repos
  1051. </h3>
  1052. <div class="row">
  1053. <div class="col">
  1054. {% if config.get('ENABLE_TICKETS', True) %}
  1055. <form action="{{ url_for(
  1056. 'ui_ns.regenerate_git',
  1057. repo=repo.name,
  1058. username=username,
  1059. namespace=repo.namespace) }}" method="post"
  1060. class="icon">
  1061. <input name="regenerate" value="tickets" type="hidden"/>
  1062. <button class="btn btn-primary" type="submit"
  1063. title="Regenerate tickets git repo">
  1064. <span class="fa fa-refresh"></span> &nbsp;Regenerate the git repo for issues
  1065. </button>
  1066. {{ form.csrf_token }}
  1067. </form>
  1068. {% endif %}
  1069. <form class="m-t-2 icon" action="{{ url_for(
  1070. 'ui_ns.regenerate_git',
  1071. repo=repo.name,
  1072. username=username,
  1073. namespace=repo.namespace) }}" method="post">
  1074. <input name="regenerate" value="requests" type="hidden"/>
  1075. <button class="btn btn-primary" type="submit"
  1076. title="Regenerate requests git repo">
  1077. <span class="fa fa-refresh"></span> &nbsp;Regenerate the git repo for requests
  1078. </button>
  1079. {{ form.csrf_token }}
  1080. </form>
  1081. </div>
  1082. </div>
  1083. </div>
  1084. {% if config.get('ENABLE_GIVE_PROJECTS', True)
  1085. and (repo.user.user == g.fas_user.username or pagure_admin)
  1086. and not repo.is_fork %}
  1087. <div class="tab-pane fade" id="giveproject" role="tabpanel" aria-labelledby="giveproject-tab">
  1088. <h3 class="font-weight-bold mb-3">
  1089. Give Project
  1090. </h3>
  1091. <div class="row">
  1092. <div class="col">
  1093. <form action="{{ url_for(
  1094. 'ui_ns.give_project',
  1095. repo=repo.name,
  1096. username=username,
  1097. namespace=repo.namespace) }}"
  1098. method="post" class="icon">
  1099. {{ tag_form.csrf_token }}
  1100. <input class="form-control" name="user" id="user"
  1101. placeholder="Start typing to search users"
  1102. value="" style="margin-bottom:1%"/>
  1103. <button class="btn btn-danger" type="submit"
  1104. onclick="return confirm('Are you sure to give {{ repo.fullname }}? \nThis is final and cannot be un-done.');"
  1105. title="Give the project to someone">
  1106. <i class="fa fa-share-square-o"></i>&nbsp; Give the {{repo.name}} project
  1107. </button>
  1108. </form>
  1109. </div>
  1110. </div>
  1111. </div>
  1112. {% endif %}
  1113. <div class="tab-pane fade" id="repospanner" role="tabpanel" aria-labelledby="repospanner-tab">
  1114. {% include 'settings_repospanner.html' %}
  1115. </div>
  1116. {% if (not repo.is_fork and config.get('ENABLE_DEL_PROJECTS', True))
  1117. or
  1118. (repo.is_fork and config.get('ENABLE_DEL_FORKS',
  1119. config.get('ENABLE_DEL_PROJECTS', True))) %}
  1120. <div class="tab-pane fade" id="deleteproject" role="tabpanel" aria-labelledby="deleteproject-tab">
  1121. <h3 class="font-weight-bold mb-3">
  1122. Delete Project
  1123. </h3>
  1124. <div class="row">
  1125. <div class="col">
  1126. {% if repo.read_only %}
  1127. <button class="btn btn-danger disabled"
  1128. title="Action disabled while project's ACLs are being refreshed">
  1129. <i class="fa fa-trash"></i>
  1130. &nbsp; Delete the {{ repo.fullname }} project
  1131. </button>
  1132. {% else %}
  1133. <form action="{{ url_for(
  1134. 'ui_ns.delete_repo',
  1135. repo=repo.name,
  1136. username=username,
  1137. namespace=repo.namespace) }}"
  1138. method="post" class="icon">
  1139. <button class="btn btn-danger" type="submit"
  1140. onclick="return confirm('Are you sure to delete {{ repo.fullname }}? \nThis is final and cannot be un-done.');"
  1141. title="Delete the project/fork">
  1142. <i class="fa fa-trash"></i>
  1143. &nbsp; Delete the {{ repo.fullname }} project
  1144. </button>
  1145. </form>
  1146. {% endif %}
  1147. </div>
  1148. </div>
  1149. </div>
  1150. {%endif %}
  1151. </div>
  1152. </div>
  1153. </div>
  1154. </div>
  1155. {% endblock %}
  1156. {% block jscripts %}
  1157. {{ super() }}
  1158. <script type="text/javascript" src="{{ url_for('static', filename='vendor/selectize/selectize.min.js') }}"></script>
  1159. <script type="text/javascript">
  1160. function show_acls(acls) {
  1161. var _txt = '<div title="ACLs details" id="show_meeting">'
  1162. + '<ul>';
  1163. for (i = 0; i < acls.length; i++) {
  1164. _txt += '<li>' + acls[i] + '</li>';
  1165. }
  1166. _txt += '</ul>' + '</div>';
  1167. var _elt = $(_txt);
  1168. var _height = $(window).height() * 0.8;
  1169. _elt.dialog({
  1170. height: 250,
  1171. width: 250,
  1172. modal: true,
  1173. cache: false,
  1174. });
  1175. }
  1176. $('#accordions').on('shown.bs.collapse', function (e) {
  1177. var _plugin = $(e.target).attr('data-plugin');
  1178. $(e.target).siblings().find("#dropdowncaret").attr('data-glyph', "caret-bottom");
  1179. if (!_plugin) {
  1180. return false;
  1181. }
  1182. var _url = "{{ url_for(
  1183. 'ui_ns.view_plugin',
  1184. repo=repo.name,
  1185. username=username,
  1186. namespace=repo.namespace,
  1187. plugin='') }}";
  1188. _url += _plugin + '/0';
  1189. console.log(_url);
  1190. $.ajax({
  1191. url: _url ,
  1192. type: 'GET',
  1193. dataType: 'html',
  1194. success: function(res) {
  1195. $("#"+e.target.id).html(res);
  1196. },
  1197. });
  1198. return false;
  1199. })
  1200. $("form").submit(function(){
  1201. $(this).find(".blank-field").remove();
  1202. });
  1203. $('#accordions').on('hide.bs.collapse', function (e) {
  1204. $(e.target).siblings().find("#dropdowncaret").attr('data-glyph', "caret-right");
  1205. })
  1206. $('.add-settings-field-row').click(function(e) {
  1207. let target = $(this).attr("data-target");
  1208. let row = $(target + ".settings-field-rows .blank-field").clone();
  1209. row.removeClass("hidden");
  1210. row.removeClass("blank-field");
  1211. $('.remove-settings-field-row', row).click(function(e) {
  1212. $(this).parent().parent().remove();
  1213. });
  1214. $(target + ".settings-field-rows").append(row);
  1215. console.log(row);
  1216. });
  1217. $('.remove-settings-field-row').click(function(e) {
  1218. $(this).parent().parent().remove();
  1219. });
  1220. {% if not repo.priorities %}
  1221. $('#default_priorities').click(function(e) {
  1222. let row = $('#priorities-list .blank-field');
  1223. var def_priorities = ['High', 'Normal', 'Low'];
  1224. for (var cnt = 0; cnt < def_priorities.length; cnt++) {
  1225. let f = row.clone();
  1226. f.removeClass("hidden");
  1227. f.removeClass("blank-field");
  1228. f.find("[name=priority_weigth]").val(cnt+1);
  1229. f.find("[name=priority_title]").val(def_priorities[cnt]);
  1230. $('.remove-settings-field-row', f).click(function(e) {
  1231. $(this).parent().parent().remove();
  1232. });
  1233. $('#priorities-list').append(f);
  1234. }
  1235. $(e.target).hide();
  1236. console.log($('#priorities'));
  1237. });
  1238. {% endif %}
  1239. {% if not repo.close_status %}
  1240. $('#default_statuses').click(function(e) {
  1241. let row = $('#status-list .blank-field');
  1242. var def_status = ['Fixed', 'Invalid', 'Duplicate', 'Insufficient Data'];
  1243. for (var cnt = 0; cnt < def_status.length; cnt++) {
  1244. let f = row.clone();
  1245. f.removeClass("hidden");
  1246. f.removeClass("blank-field");
  1247. f.find("[name=close_status]").val(def_status[cnt]);
  1248. $('.remove-settings-field-row', f).click(function(e) {
  1249. $(this).parent().parent().remove();
  1250. });
  1251. $('#status-list').append(f);
  1252. }
  1253. $(e.target).hide();
  1254. });
  1255. $('#default_close_status').click(function(e) {
  1256. let form = $('#close_sstatus>div:last-child');
  1257. form.find('input[type=text], textarea').val('');
  1258. $('#close_sstatus').html('');
  1259. var def_closestatus = ['Fixed', 'Invalid', 'Duplicate', 'Insufficient Data'];
  1260. for (var cnt = 0; cnt < def_closestatus.length; cnt++) {
  1261. let f = form.clone();
  1262. f.find("[name=close_status]").val(def_closestatus[cnt]);
  1263. $('#close_sstatus').append(f);
  1264. }
  1265. console.log($('#close_sstatus'));
  1266. });
  1267. {% endif %}
  1268. var first_new_tag = 1;
  1269. $('#new_tag').click(function(e) {
  1270. console.log('new tag');
  1271. console.log($('#tagcolor'));
  1272. if (first_new_tag == 1){
  1273. // Only display the Tag row the first time Add New Tag is clicked
  1274. $('#tagcolor').append(
  1275. '<div class="row">\
  1276. <div class="col-sm-4">\
  1277. <strong>New Tag</strong>\
  1278. </div>\
  1279. <div class="col-sm-5">\
  1280. <strong>Description</strong>\
  1281. </div>\
  1282. <div class="col-sm-3">\
  1283. <strong>Tag Color</strong>\
  1284. </div>\
  1285. </div>');
  1286. first_new_tag = 0;
  1287. }
  1288. $('#tagcolor').append(
  1289. '<div class="row p-t-1"> \
  1290. <div class="col-sm-4 p-r-0">\
  1291. <input type="text" name="tag"\
  1292. value="" size="3" class="form-control"/>\
  1293. </div>\
  1294. <div class="col-sm-5 p-r-0">\
  1295. <input type="text" name="tag_description" placeholder="(optional)"\
  1296. value="" size="15" class="form-control"/>\
  1297. </div>\
  1298. <div class="col-sm-2 p-r-0">\
  1299. <input type="color" name="tag_color" class="form-control c-select" \
  1300. onchange="clickColor(0, -1, -1, 5)" /> \
  1301. </div>\
  1302. <div class="col-sm-1 p-r-0">\
  1303. <span class="oi del_tag_tbn" data-glyph="circle-x"></span>\
  1304. </div>\
  1305. </div>'
  1306. );
  1307. set_up_del_tag_tbn();
  1308. });
  1309. function set_up_del_tag_tbn() {
  1310. $('.del_tag_tbn').click(function(e) {
  1311. $(this).parent().parent().remove();
  1312. });
  1313. }
  1314. $('.extend-form').click(function(e) {
  1315. const tgt = $(this).attr('data-target');
  1316. let form = $(tgt + ' > div:last-child').clone();
  1317. form.find('input[type=text], textarea').val('');
  1318. if (tgt == '#milestones'){
  1319. var _b = $(form.find('.milestone_order_up'));
  1320. const idx = parseInt(_b.attr('data-stone'));
  1321. form.removeClass('milestone_inactive');
  1322. form.attr('id', 'milestone_' + (idx + 1 ));
  1323. _b.attr('data-stone', (idx + 1))
  1324. var _b2 = $(form.find('.milestone_order_bottom'));
  1325. _b2.attr('data-stone', (idx + 1))
  1326. var _d = form.find('input[name=milestone_date_' + idx + ']');
  1327. $(_d).attr('name', 'milestone_date_' + (idx + 1 ));
  1328. var _a = form.find('input[name=active_milestone_' + idx + ']');
  1329. $(_a).attr('name', 'active_milestone_' + (idx + 1 ));
  1330. $(_a).prop('checked', true);
  1331. } else if (tgt == '#milestones_show'){
  1332. var _el = $('.milestone_inactive')
  1333. if (_el.css('display') == 'none'){
  1334. _el.css('display', 'flex');
  1335. } else {
  1336. _el.hide();
  1337. }
  1338. }
  1339. $(tgt).append(form);
  1340. });
  1341. $('.milestone_order_up').click(function(e) {
  1342. const idx = parseInt($(this).attr('data-stone'));
  1343. let field = $('#milestone_' + idx);
  1344. if (field.prev('.milestone').length > 0){
  1345. field.prev('.milestone').before(field.detach());
  1346. }
  1347. });
  1348. $('.milestone_order_bottom').click(function(e) {
  1349. const idx = parseInt($(this).attr('data-stone'));
  1350. let field = $('#milestone_' + idx);
  1351. if (field.next('.milestone').length > 0){
  1352. field.next('.milestone').after(field.detach());
  1353. }
  1354. });
  1355. {% if config.get('ENABLE_GIVE_PROJECTS', True)
  1356. and repo.user.user == g.fas_user.username
  1357. and not repo.is_fork %}
  1358. $('#user').selectize({
  1359. valueField: 'user',
  1360. labelField: 'user',
  1361. searchField: 'user',
  1362. maxItems: 1,
  1363. create: false,
  1364. load: function(query, callback) {
  1365. if (!query.length) return callback();
  1366. $.getJSON(
  1367. "{{ url_for('api_ns.api_users') }}", {
  1368. pattern: query.term
  1369. },
  1370. function( data ) {
  1371. callback( data.users.map(function(x) { return { user: x }; }) );
  1372. }
  1373. );
  1374. }
  1375. });
  1376. {% endif %}
  1377. </script>
  1378. <script type="text/javascript">
  1379. $(document).ready(function() {
  1380. $('#nav-tab a.nav-link').on('shown.bs.tab', function (e) {
  1381. window.location.hash = e.target.hash+'-tab';
  1382. window.scrollTo(0,0);
  1383. });
  1384. if (!window.location.hash){
  1385. window.location.hash = "#projectdetails-tab"
  1386. }
  1387. window.onhashchange = function () {
  1388. $(window.location.hash).tab('show');
  1389. }
  1390. const anchor = window.location.hash;
  1391. console.log(anchor);
  1392. $(anchor).tab('show');
  1393. window.scrollTo(0,0);
  1394. });
  1395. </script>
  1396. {% endblock %}