1
0

PersonalAccessTokens.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <style scoped>
  2. .action-link {
  3. cursor: pointer;
  4. }
  5. </style>
  6. <template>
  7. <div>
  8. <div>
  9. <div class="card card-default mb-4">
  10. <div class="card-header font-weight-bold bg-white">
  11. <div style="display: flex; justify-content: space-between; align-items: center;">
  12. <span>
  13. Personal Access Tokens
  14. </span>
  15. <a class="action-link" tabindex="-1" @click="showCreateTokenForm">
  16. Create New Token
  17. </a>
  18. </div>
  19. </div>
  20. <div class="card-body">
  21. <!-- No Tokens Notice -->
  22. <p class="mb-0" v-if="tokens.length === 0">
  23. You have not created any personal access tokens.
  24. </p>
  25. <!-- Personal Access Tokens -->
  26. <table class="table table-borderless mb-0" v-if="tokens.length > 0">
  27. <thead>
  28. <tr>
  29. <th>Name</th>
  30. <th></th>
  31. </tr>
  32. </thead>
  33. <tbody>
  34. <tr v-for="token in tokens">
  35. <!-- Client Name -->
  36. <td style="vertical-align: middle;">
  37. {{ token.name }}
  38. </td>
  39. <!-- Delete Button -->
  40. <td style="vertical-align: middle;">
  41. <a class="action-link text-danger" @click="revoke(token)">
  42. Delete
  43. </a>
  44. </td>
  45. </tr>
  46. </tbody>
  47. </table>
  48. </div>
  49. </div>
  50. </div>
  51. <!-- Create Token Modal -->
  52. <div class="modal fade" id="modal-create-token" tabindex="-1" role="dialog">
  53. <div class="modal-dialog">
  54. <div class="modal-content">
  55. <div class="modal-header">
  56. <h4 class="modal-title">
  57. Create Token
  58. </h4>
  59. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
  60. </div>
  61. <div class="modal-body">
  62. <!-- Form Errors -->
  63. <div class="alert alert-danger" v-if="form.errors.length > 0">
  64. <p class="mb-0"><strong>Whoops!</strong> Something went wrong!</p>
  65. <br>
  66. <ul>
  67. <li v-for="error in form.errors">
  68. {{ error }}
  69. </li>
  70. </ul>
  71. </div>
  72. <!-- Create Token Form -->
  73. <form role="form" @submit.prevent="store">
  74. <!-- Name -->
  75. <div class="form-group row">
  76. <label class="col-md-4 col-form-label">Name</label>
  77. <div class="col-md-6">
  78. <input id="create-token-name" type="text" class="form-control" name="name" v-model="form.name" autocomplete="off">
  79. </div>
  80. </div>
  81. <!-- Scopes -->
  82. <div class="form-group row" v-if="scopes.length > 0">
  83. <label class="col-md-4 col-form-label">Scopes</label>
  84. <div class="col-md-6">
  85. <div v-for="scope in scopes">
  86. <div class="checkbox">
  87. <label>
  88. <input type="checkbox"
  89. @click="toggleScope(scope.id)"
  90. :checked="scopeIsAssigned(scope.id)">
  91. {{ scope.id }}
  92. </label>
  93. </div>
  94. </div>
  95. </div>
  96. </div>
  97. </form>
  98. </div>
  99. <!-- Modal Actions -->
  100. <div class="modal-footer">
  101. <button type="button" class="btn btn-secondary font-weight-bold" data-dismiss="modal">Close</button>
  102. <button type="button" class="btn btn-primary font-weight-bold" @click="store">
  103. Create
  104. </button>
  105. </div>
  106. </div>
  107. </div>
  108. </div>
  109. <!-- Access Token Modal -->
  110. <div class="modal fade" id="modal-access-token" tabindex="-1" role="dialog">
  111. <div class="modal-dialog">
  112. <div class="modal-content">
  113. <div class="modal-header">
  114. <h4 class="modal-title">
  115. Personal Access Token
  116. </h4>
  117. <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
  118. </div>
  119. <div class="modal-body">
  120. <p>
  121. Here is your new personal access token. This is the only time it will be shown so don't lose it!
  122. You may now use this token to make API requests.
  123. </p>
  124. <textarea class="form-control" rows="10">{{ accessToken }}</textarea>
  125. </div>
  126. <!-- Modal Actions -->
  127. <div class="modal-footer">
  128. <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
  129. </div>
  130. </div>
  131. </div>
  132. </div>
  133. </div>
  134. </template>
  135. <script>
  136. export default {
  137. /*
  138. * The component's data.
  139. */
  140. data() {
  141. return {
  142. accessToken: null,
  143. tokens: [],
  144. scopes: [],
  145. form: {
  146. name: '',
  147. scopes: [],
  148. errors: []
  149. }
  150. };
  151. },
  152. /**
  153. * Prepare the component (Vue 1.x).
  154. */
  155. ready() {
  156. this.prepareComponent();
  157. },
  158. /**
  159. * Prepare the component (Vue 2.x).
  160. */
  161. mounted() {
  162. this.prepareComponent();
  163. },
  164. methods: {
  165. /**
  166. * Prepare the component.
  167. */
  168. prepareComponent() {
  169. this.getTokens();
  170. this.getScopes();
  171. $('#modal-create-token').on('shown.bs.modal', () => {
  172. $('#create-token-name').focus();
  173. });
  174. },
  175. /**
  176. * Get all of the personal access tokens for the user.
  177. */
  178. getTokens() {
  179. axios.get('/oauth/personal-access-tokens')
  180. .then(response => {
  181. this.tokens = response.data;
  182. });
  183. },
  184. /**
  185. * Get all of the available scopes.
  186. */
  187. getScopes() {
  188. axios.get('/oauth/scopes')
  189. .then(response => {
  190. this.scopes = response.data;
  191. });
  192. },
  193. /**
  194. * Show the form for creating new tokens.
  195. */
  196. showCreateTokenForm() {
  197. $('#modal-create-token').modal('show');
  198. },
  199. /**
  200. * Create a new personal access token.
  201. */
  202. store() {
  203. this.accessToken = null;
  204. this.form.errors = [];
  205. axios.post('/oauth/personal-access-tokens', this.form)
  206. .then(response => {
  207. this.form.name = '';
  208. this.form.scopes = [];
  209. this.form.errors = [];
  210. this.tokens.push(response.data.token);
  211. this.showAccessToken(response.data.accessToken);
  212. })
  213. .catch(error => {
  214. if (typeof error.response.data === 'object') {
  215. this.form.errors = _.flatten(_.toArray(error.response.data.errors));
  216. } else {
  217. this.form.errors = ['Something went wrong. Please try again.'];
  218. }
  219. });
  220. },
  221. /**
  222. * Toggle the given scope in the list of assigned scopes.
  223. */
  224. toggleScope(scope) {
  225. if (this.scopeIsAssigned(scope)) {
  226. this.form.scopes = _.reject(this.form.scopes, s => s == scope);
  227. } else {
  228. this.form.scopes.push(scope);
  229. }
  230. },
  231. /**
  232. * Determine if the given scope has been assigned to the token.
  233. */
  234. scopeIsAssigned(scope) {
  235. return _.indexOf(this.form.scopes, scope) >= 0;
  236. },
  237. /**
  238. * Show the given access token to the user.
  239. */
  240. showAccessToken(accessToken) {
  241. $('#modal-create-token').modal('hide');
  242. this.accessToken = accessToken;
  243. $('#modal-access-token').modal('show');
  244. },
  245. /**
  246. * Revoke the given token.
  247. */
  248. revoke(token) {
  249. axios.delete('/oauth/personal-access-tokens/' + token.id)
  250. .then(response => {
  251. this.getTokens();
  252. });
  253. }
  254. }
  255. }
  256. </script>