settings.html 66 KB

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