You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

581 lines
23 KiB

  1. {% extends "base.html" %}
  2. {% load compress static hc_extras %}
  3. {% block title %}Project Settings - {{ project }}{% endblock %}
  4. {% block content %}
  5. {% with project.transfer_request as transfer_request %}
  6. <div class="row">
  7. <div class="col-sm-9 col-md-6">
  8. {% for message in messages %}
  9. <p class="alert alert-{{ message.tags }}">{{ message }}</p>
  10. {% endfor %}
  11. {% if transfer_request and transfer_request.user == request.user %}
  12. {% with can_accept=transfer_request.can_accept %}
  13. <div id="transfer-request" class="panel">
  14. <div class="panel-body settings-block">
  15. <h2>Ownership Transfer Request</h2>
  16. <p>
  17. <strong>{{ project.owner.email }}</strong> would like to transfer
  18. the ownership of this project to you.
  19. </p>
  20. {% if not can_accept %}
  21. {% with num_checks=project.num_checks num_available=request.profile.num_checks_available %}
  22. <p>
  23. This project has
  24. <strong>{{ num_checks }} check{{ num_checks|pluralize}}</strong>,
  25. but your account only has space for
  26. <strong>{{ num_available }} additional check{{ num_available|pluralize }}</strong>.
  27. To accept the transfer, please
  28. <a href="{% url 'hc-billing' %}">upgrade your account first!</a>
  29. </p>
  30. {% endwith%}
  31. {% endif %}
  32. <div class="pull-right">
  33. <form method="post">
  34. {% csrf_token %}
  35. <button
  36. type="submit"
  37. name="reject_transfer"
  38. class="btn btn-default">Reject</button>
  39. <button
  40. type="submit"
  41. name="accept_transfer"
  42. {% if not can_accept %}disabled{% endif %}
  43. class="btn btn-primary">Accept</button>
  44. </form>
  45. </div>
  46. </div>
  47. </div>
  48. {% endwith %}
  49. {% endif %}
  50. <div class="panel panel-{{ project_name_status|default:'default' }}">
  51. <div class="panel-body settings-block">
  52. <h2>Project Name</h2>
  53. {{ project }}
  54. {% if rw %}
  55. <a
  56. href="#"
  57. class="btn btn-default pull-right"
  58. data-toggle="modal"
  59. data-target="#set-project-name-modal">Change Project Name</a>
  60. {% endif %}
  61. </div>
  62. {% if project_name_updated %}
  63. <div class="panel-footer">
  64. Project name updated
  65. </div>
  66. {% endif %}
  67. </div>
  68. <div class="panel panel-{{ api_status|default:'default' }}">
  69. <div class="panel-body settings-block">
  70. <h2>API Access</h2>
  71. {% if project.api_key %}
  72. {% if show_api_keys %}
  73. <p>
  74. API key: <br />
  75. <pre>{{ project.api_key }}</pre>
  76. </p>
  77. {% if project.api_key_readonly %}
  78. <p>
  79. API key (read-only): <br />
  80. <pre>{{ project.api_key_readonly }}</pre>
  81. </p>
  82. <p>Related links:</p>
  83. <ul>
  84. <li><a href="{% url 'hc-serve-doc' 'api' %}">API documentation</a></li>
  85. {% if enable_prometheus %}
  86. <li>
  87. <a href="{% url 'hc-metrics' project.code project.api_key_readonly %}">Prometheus metrics endpoint</a>
  88. </li>
  89. {% endif %}
  90. <li>
  91. <a href="{{ project.dashboard_url }}">Read-only dashboard</a>
  92. (<a href="https://github.com/healthchecks/dashboard/#security">security considerations</a>)
  93. </li>
  94. </ul>
  95. {% endif %}
  96. <button
  97. data-toggle="modal"
  98. data-target="#revoke-api-key-modal"
  99. class="btn btn-danger pull-right">Revoke</button>
  100. {% else %}
  101. <form method="post">
  102. <span class="ic-ok"></span>
  103. API access is enabled.
  104. {% csrf_token %}
  105. {% if rw %}
  106. <button
  107. type="submit"
  108. name="show_api_keys"
  109. class="btn btn-default pull-right">Show API Keys</button>
  110. {% endif %}
  111. </form>
  112. {% endif %}
  113. {% else %}
  114. <span class="ic-cancel"></span>
  115. API access is disabled.
  116. <form method="post">
  117. {% csrf_token %}
  118. <button
  119. type="submit"
  120. name="create_api_keys"
  121. class="btn btn-default pull-right">Create API Keys</button>
  122. </form>
  123. {% endif %}
  124. </div>
  125. {% if api_keys_created %}
  126. <div class="panel-footer">
  127. API keys created
  128. </div>
  129. {% endif %}
  130. {% if api_keys_revoked %}
  131. <div class="panel-footer">
  132. API keys revoked
  133. </div>
  134. {% endif %}
  135. </div>
  136. {% with invite_suggestions=project.invite_suggestions %}
  137. <div class="panel panel-{{ team_status|default:'default' }}">
  138. <div class="panel-body settings-block">
  139. <h2>Team Access</h2>
  140. {% if memberships or invite_suggestions %}
  141. <table id="team-table" class="table">
  142. <tr>
  143. <th>Email</th>
  144. <th>Role</th>
  145. <th></th>
  146. </tr>
  147. <tr>
  148. <td class="email">{{ project.owner.email }}</td>
  149. <td>Owner</td>
  150. <td></td>
  151. </tr>
  152. {% for m in memberships %}
  153. <tr>
  154. <td class="email">{{ m.user.email }}</td>
  155. <td>{{ m.get_role_display }}</td>
  156. <td>
  157. {% if is_manager and m.user != request.user %}
  158. <a
  159. href="#"
  160. data-email="{{ m.user.email }}"
  161. class="pull-right member-remove">Remove</a>
  162. {% endif %}
  163. </td>
  164. </tr>
  165. {% endfor %}
  166. {% if is_manager and invite_suggestions %}
  167. <tr id="suggestions-row">
  168. <td colspan="3">
  169. Add Users from Other Teams
  170. </td>
  171. </tr>
  172. {% for user in invite_suggestions %}
  173. <tr class="invite-suggestion">
  174. <td>{{ user.email }} </td>
  175. <td></td>
  176. <td>
  177. <a
  178. href="#"
  179. data-email="{{ user.email }}"
  180. class="pull-right add-to-team">Add to Team</a>
  181. </td>
  182. </tr>
  183. {% endfor %}
  184. {% endif %}
  185. </table>
  186. {% else %}
  187. <p>
  188. <strong>Invite team members to your project.</strong>
  189. Share access to your checks and configured integrations
  190. without having to share login details.
  191. </p>
  192. {% endif %}
  193. <br />
  194. {% if is_manager %}
  195. {% if project.can_invite_new_users %}
  196. <a
  197. href="#"
  198. class="btn btn-primary pull-right"
  199. data-toggle="modal"
  200. data-target="#invite-team-member-modal">Invite a Team Member</a>
  201. {% else %}
  202. <div class="alert alert-info">
  203. <strong>Team size limit reached.</strong>
  204. {% if is_owner %}
  205. To invite new members by email, please
  206. <a href="{% url 'hc-pricing' %}">upgrade your account!</a>
  207. {% else %}
  208. To invite new members, please ask project's owner
  209. to upgrade their account.
  210. {% endif %}
  211. </div>
  212. {% endif %}
  213. {% endif %}
  214. </div>
  215. {% endwith %}
  216. {% if team_member_invited %}
  217. <div class="panel-footer">
  218. {{ team_member_invited }} invited to team
  219. </div>
  220. {% endif %}
  221. {% if team_member_duplicate %}
  222. <div class="panel-footer">
  223. {{ team_member_duplicate }} is already a member
  224. </div>
  225. {% endif %}
  226. {% if team_member_removed %}
  227. <div class="panel-footer">
  228. {{ team_member_removed }} removed from team
  229. </div>
  230. {% endif %}
  231. </div>
  232. {% if is_owner %}
  233. <div class="panel panel-{{ transfer_status|default:'default' }}"">
  234. <div class="panel-body settings-block">
  235. <h2>Transfer Ownership</h2>
  236. {% if transfer_request %}
  237. <form method="post">
  238. {% csrf_token %}
  239. <button
  240. type="submit"
  241. name="cancel_transfer"
  242. class="btn btn-default pull-right">Cancel Transfer</button>
  243. </form>
  244. Transfer initiated, awaiting confirmation from
  245. <strong>{{ transfer_request.user.email }}</strong>.
  246. {% else %}
  247. <a href="#"
  248. class="btn btn-default pull-right"
  249. data-toggle="modal"
  250. data-target="#transfer-modal">Transfer Project&hellip;</a>
  251. Transfer this project to a team member.
  252. {% endif %}
  253. </div>
  254. {% if transfer_initiated %}
  255. <div class="panel-footer">
  256. Transfer initiated!
  257. </div>
  258. {% endif %}
  259. {% if transfer_cancelled %}
  260. <div class="panel-footer">
  261. Transfer cancelled!
  262. </div>
  263. {% endif %}
  264. </div>
  265. {% endif %}
  266. {% if is_owner %}
  267. <div class="panel panel-default">
  268. <div class="panel-body settings-block">
  269. {% csrf_token %}
  270. <h2>Remove Project</h2>
  271. <a href="#"
  272. id="remove-project"
  273. class="btn btn-default pull-right"
  274. data-toggle="modal"
  275. data-target="#remove-project-modal">Remove Project</a>
  276. This will permanently remove project {{ project }}.
  277. <form action="{% url 'hc-remove-project' project.code %}" method="post">
  278. </form>
  279. </div>
  280. </div>
  281. {% endif %}
  282. </div>
  283. </div>
  284. <div id="revoke-api-key-modal" class="modal">
  285. <div class="modal-dialog">
  286. <form id="revoke-api-key-form" method="post">
  287. {% csrf_token %}
  288. <div class="modal-content">
  289. <div class="modal-header">
  290. <button type="button" class="close" data-dismiss="modal">&times;</button>
  291. <h4>Revoke API Keys?</h4>
  292. </div>
  293. <div class="modal-body">
  294. <p>You are about to revoke your current API keys.</p>
  295. <p>Afterwards, you can create new API keys, but there will
  296. be <strong>no way of getting the current API
  297. keys back</strong>.
  298. </p>
  299. <p>Are you sure?</p>
  300. </div>
  301. <div class="modal-footer">
  302. <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
  303. <button
  304. type="submit"
  305. name="revoke_api_keys"
  306. class="btn btn-danger">Revoke API Keys</button>
  307. </div>
  308. </div>
  309. </form>
  310. </div>
  311. </div>
  312. <div id="remove-team-member-modal" class="modal">
  313. <div class="modal-dialog">
  314. <form id="remove-team-member-form" method="post">
  315. {% csrf_token %}
  316. <div class="modal-content">
  317. <div class="modal-header">
  318. <button type="button" class="close" data-dismiss="modal">&times;</button>
  319. <h4>Remove Team Member</h4>
  320. </div>
  321. <div class="modal-body">
  322. <p>You are about to remove <strong id="rtm-email"></strong> from the project.</p>
  323. <p>Are you sure?</p>
  324. <input
  325. type="hidden"
  326. name="email"
  327. id="remove-team-member-email" />
  328. </div>
  329. <div class="modal-footer">
  330. <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
  331. <button
  332. type="submit"
  333. name="remove_team_member"
  334. class="btn btn-danger">Remove Member from Project</button>
  335. </div>
  336. </div>
  337. </form>
  338. </div>
  339. </div>
  340. <div id="invite-team-member-modal" class="modal">
  341. <div class="modal-dialog">
  342. <form method="post" class="form-horizontal">
  343. {% csrf_token %}
  344. <input type="hidden" name="invite_team_member" value="1" />
  345. <div class="modal-content">
  346. <div class="modal-header">
  347. <button type="button" class="close" data-dismiss="modal">&times;</button>
  348. <h4>Invite a Team Member</h4>
  349. </div>
  350. <div class="modal-body">
  351. <div class="form-group">
  352. <label for="itm-email" class="col-sm-3 control-label">Email</label>
  353. <div class="col-sm-8">
  354. <input
  355. type="email"
  356. class="form-control"
  357. id="itm-email"
  358. name="email"
  359. maxlength="254"
  360. placeholder="[email protected]">
  361. </div>
  362. </div>
  363. <div class="form-group">
  364. <label class="col-sm-3 control-label">Access Level</label>
  365. <div class="col-sm-8">
  366. <label class="radio-container">
  367. <input
  368. type="radio"
  369. name="role"
  370. value="w"
  371. checked>
  372. <span class="radiomark"></span>
  373. Team Member
  374. <span class="help-block">
  375. Can create and manage checks and integrations.
  376. Cannot access your account's billing settings.
  377. </span>
  378. </label>
  379. <label class="radio-container">
  380. <input
  381. type="radio"
  382. name="role"
  383. value="m">
  384. <span class="radiomark"></span>
  385. Manager
  386. <span class="help-block">
  387. Same as Team Member, plus can invite and remove
  388. other members.
  389. </span>
  390. </label>
  391. <label class="radio-container">
  392. <input
  393. type="radio"
  394. name="role"
  395. value="r">
  396. <span class="radiomark"></span>
  397. Read-only
  398. <span class="help-block">
  399. Can view checks and integrations, but cannot
  400. modify anything. Cannot access project's API keys.
  401. </span>
  402. </label>
  403. </div>
  404. </div>
  405. </div>
  406. <div class="modal-footer">
  407. <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
  408. <button
  409. type="submit"
  410. name="invite_team_member"
  411. class="btn btn-primary">Send Invite</button>
  412. </div>
  413. </div>
  414. </form>
  415. </div>
  416. </div>
  417. <div id="set-project-name-modal" class="modal">
  418. <div class="modal-dialog">
  419. <form method="post" class="form-horizontal">
  420. {% csrf_token %}
  421. <div class="modal-content">
  422. <div class="modal-header">
  423. <button type="button" class="close" data-dismiss="modal">&times;</button>
  424. <h4>Change Project Name</h4>
  425. </div>
  426. <div class="modal-body">
  427. <div class="form-group">
  428. <label for="project-name" class="col-sm-4 control-label">Project Name</label>
  429. <div class="col-sm-7">
  430. <input
  431. type="text"
  432. class="form-control"
  433. id="project-name"
  434. name="name"
  435. maxlength="60"
  436. value="{{ project }}">
  437. </div>
  438. </div>
  439. </div>
  440. <div class="modal-footer">
  441. <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
  442. <button
  443. type="submit"
  444. name="set_project_name"
  445. class="btn btn-primary">Set Project Name</button>
  446. </div>
  447. </div>
  448. </form>
  449. </div>
  450. </div>
  451. <div id="remove-project-modal" class="modal">
  452. <div class="modal-dialog">
  453. <form method="post" action="{% url 'hc-remove-project' project.code %}">
  454. {% csrf_token %}
  455. <div class="modal-content">
  456. <div class="modal-header">
  457. <button type="button" class="close" data-dismiss="modal">&times;</button>
  458. <h4>Remove "{{ project }}"?</h4>
  459. </div>
  460. <div class="modal-body">
  461. <p>Danger zone! You are about to permanently remove
  462. project <strong>{{ project }}</strong> and all
  463. of its associated checks and integrations. Are you sure?
  464. </p>
  465. </div>
  466. <div class="modal-footer">
  467. <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
  468. <button
  469. type="submit"
  470. class="btn btn-danger">Remove Project</button>
  471. </div>
  472. </div>
  473. </form>
  474. </div>
  475. </div>
  476. {% if is_owner and not transfer_request %}
  477. <div id="transfer-modal" class="modal">
  478. <div class="modal-dialog">
  479. <form
  480. class="form-horizontal"
  481. method="post">
  482. {% csrf_token %}
  483. <input type="hidden" name="transfer_project" value="1" />
  484. <div class="modal-content">
  485. <div class="modal-header">
  486. <button type="button" class="close" data-dismiss="modal">&times;</button>
  487. <h4>Transfer Ownership</h4>
  488. </div>
  489. <div class="modal-body">
  490. {% if memberships %}
  491. <div class="form-group">
  492. <label for="update-name-input" class="col-sm-4 control-label">
  493. Choose owner
  494. </label>
  495. <div class="col-sm-7">
  496. <select
  497. id="new-owner"
  498. name="email"
  499. title="Select..."
  500. class="form-control selectpicker">
  501. {% for m in memberships %}
  502. <option>{{ m.user.email }}</option>
  503. {% endfor %}
  504. </select>
  505. </div>
  506. </div>
  507. {% else %}
  508. <p>
  509. This project currently has no team members.
  510. To transfer the ownership of this project, please start by
  511. inviting the new owner as a team member.
  512. </p>
  513. {% endif %}
  514. </div>
  515. <div class="modal-footer">
  516. <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
  517. <button
  518. id="transfer-confirm"
  519. disabled
  520. type="submit"
  521. class="btn btn-primary">Initiate Transfer</button>
  522. </div>
  523. </div>
  524. </form>
  525. </div>
  526. </div>
  527. {% endif %}
  528. {% endwith %}
  529. {% endblock %}
  530. {% block scripts %}
  531. {% compress js %}
  532. <script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
  533. <script src="{% static 'js/bootstrap.min.js' %}"></script>
  534. <script src="{% static 'js/bootstrap-select.min.js' %}"></script>
  535. <script src="{% static 'js/project.js' %}"></script>
  536. {% endcompress %}
  537. {% endblock %}