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.

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