diff options
author | Johannes Zellner <johannes@cloudron.io> | 2019-08-07 22:33:23 +0200 |
---|---|---|
committer | Johannes Zellner <johannes@cloudron.io> | 2019-08-07 22:33:23 +0200 |
commit | c2c00fca7dccb6e512a0f01bc87db129538765ef (patch) | |
tree | 3b872bed1587231a22d24fe8aaf3043565900f3b /frontend | |
parent | d5940df06a4f498176dad293f66607fb69eb2a28 (diff) | |
download | Surfer-c2c00fca7dccb6e512a0f01bc87db129538765ef.tar.gz Surfer-c2c00fca7dccb6e512a0f01bc87db129538765ef.tar.zst Surfer-c2c00fca7dccb6e512a0f01bc87db129538765ef.zip |
Add access token ui and rest api
Diffstat (limited to 'frontend')
-rw-r--r-- | frontend/css/style.css | 9 | ||||
-rw-r--r-- | frontend/index.html | 16 | ||||
-rw-r--r-- | frontend/js/app.js | 44 |
3 files changed, 68 insertions, 1 deletions
diff --git a/frontend/css/style.css b/frontend/css/style.css index 901de34..b43d6fe 100644 --- a/frontend/css/style.css +++ b/frontend/css/style.css | |||
@@ -89,3 +89,12 @@ a:hover, a:focus { | |||
89 | align-items: center; | 89 | align-items: center; |
90 | justify-content: center; | 90 | justify-content: center; |
91 | } | 91 | } |
92 | |||
93 | .access-token-input { | ||
94 | padding: 5px 0; | ||
95 | width: 450px; | ||
96 | } | ||
97 | |||
98 | .access-token-input > input, .access-token-input i { | ||
99 | cursor: copy !important; | ||
100 | } | ||
diff --git a/frontend/index.html b/frontend/index.html index 2d97e1c..20154da 100644 --- a/frontend/index.html +++ b/frontend/index.html | |||
@@ -36,6 +36,21 @@ | |||
36 | </span> | 36 | </span> |
37 | </el-dialog> | 37 | </el-dialog> |
38 | 38 | ||
39 | <el-dialog title="Access Tokens" :visible.sync="accessTokensDialogVisible" width="30%"> | ||
40 | Tokens can be used with the surfer <a href="https://www.npmjs.com/package/cloudron-surfer" target="_blank">cli tool</a> or using the Api directly. | ||
41 | They are shared between all users. | ||
42 | <br/> | ||
43 | <br/> | ||
44 | <div> | ||
45 | <div v-for="accessToken in accessTokens"> | ||
46 | <el-input suffix-icon="el-icon-copy-document" v-model="accessToken" class="access-token-input" @focus="onCopyAccessToken" size="small"></el-input> | ||
47 | <el-button icon="el-icon-delete" type="danger" size="small" @click="onDeleteAccessToken(accessToken)"></el-button> | ||
48 | </div> | ||
49 | </div> | ||
50 | <br/> | ||
51 | <el-button @click="onCreateAccessToken()" size="small" type="primary">Create Access Token</el-button> | ||
52 | </el-dialog> | ||
53 | |||
39 | <el-header> | 54 | <el-header> |
40 | <el-row type="flex" justify="space-between"> | 55 | <el-row type="flex" justify="space-between"> |
41 | <div style="padding: 7px;"> | 56 | <div style="padding: 7px;"> |
@@ -66,6 +81,7 @@ | |||
66 | </el-dropdown-item> | 81 | </el-dropdown-item> |
67 | <el-dropdown-item disabled divided>WebDAV Endpoint</el-dropdown-item> | 82 | <el-dropdown-item disabled divided>WebDAV Endpoint</el-dropdown-item> |
68 | <el-dropdown-item><a href="/_webdav/" target="_blank">{{ origin }}/_webdav/</a></el-dropdown-item> | 83 | <el-dropdown-item><a href="/_webdav/" target="_blank">{{ origin }}/_webdav/</a></el-dropdown-item> |
84 | <el-dropdown-item command="apiAccess" divided><i class="el-icon-connection"></i> Access Tokens</el-dropdown-item> | ||
69 | <el-dropdown-item command="about" divided><i class="el-icon-info"></i> About</el-dropdown-item> | 85 | <el-dropdown-item command="about" divided><i class="el-icon-info"></i> About</el-dropdown-item> |
70 | <el-dropdown-item command="logout" id="logoutButton"><i class="el-icon-circle-close"></i> Logout</el-dropdown-item> | 86 | <el-dropdown-item command="logout" id="logoutButton"><i class="el-icon-circle-close"></i> Logout</el-dropdown-item> |
71 | </el-dropdown-menu> | 87 | </el-dropdown-menu> |
diff --git a/frontend/js/app.js b/frontend/js/app.js index d99a840..05cbe9c 100644 --- a/frontend/js/app.js +++ b/frontend/js/app.js | |||
@@ -43,6 +43,8 @@ function initWithToken(accessToken) { | |||
43 | app.folderListingEnabled = !!result.body.folderListingEnabled; | 43 | app.folderListingEnabled = !!result.body.folderListingEnabled; |
44 | 44 | ||
45 | loadDirectory(decode(window.location.hash.slice(1))); | 45 | loadDirectory(decode(window.location.hash.slice(1))); |
46 | |||
47 | app.refreshAccessTokens(); | ||
46 | }); | 48 | }); |
47 | }); | 49 | }); |
48 | } | 50 | } |
@@ -278,7 +280,9 @@ var app = new Vue({ | |||
278 | password: '', | 280 | password: '', |
279 | busy: false | 281 | busy: false |
280 | }, | 282 | }, |
281 | entries: [] | 283 | entries: [], |
284 | accessTokens: [], | ||
285 | accessTokensDialogVisible: false | ||
282 | }, | 286 | }, |
283 | methods: { | 287 | methods: { |
284 | onLogin: function () { | 288 | onLogin: function () { |
@@ -312,6 +316,8 @@ var app = new Vue({ | |||
312 | }).then(function () {}).catch(function () {}); | 316 | }).then(function () {}).catch(function () {}); |
313 | } else if (command === 'logout') { | 317 | } else if (command === 'logout') { |
314 | logout(); | 318 | logout(); |
319 | } else if (command === 'apiAccess') { | ||
320 | this.accessTokensDialogVisible = true; | ||
315 | } | 321 | } |
316 | }, | 322 | }, |
317 | onDownload: function (entry) { | 323 | onDownload: function (entry) { |
@@ -415,6 +421,42 @@ var app = new Vue({ | |||
415 | }); | 421 | }); |
416 | }).catch(function () {}); | 422 | }).catch(function () {}); |
417 | }, | 423 | }, |
424 | refreshAccessTokens: function () { | ||
425 | var that = this; | ||
426 | |||
427 | superagent.get('/api/tokens').query({ access_token: localStorage.accessToken }).end(function (error, result) { | ||
428 | if (error && !result) return that.$message.error(error.message); | ||
429 | |||
430 | that.accessTokens = result.body.accessTokens; | ||
431 | }); | ||
432 | }, | ||
433 | onCopyAccessToken: function (event) { | ||
434 | event.target.select(); | ||
435 | document.execCommand('copy'); | ||
436 | |||
437 | this.$message({ type: 'success', message: 'Access token copied to clipboard' }); | ||
438 | }, | ||
439 | onCreateAccessToken: function () { | ||
440 | var that = this; | ||
441 | |||
442 | superagent.post('/api/tokens').query({ access_token: localStorage.accessToken }).end(function (error, result) { | ||
443 | if (error && !result) return that.$message.error(error.message); | ||
444 | |||
445 | that.refreshAccessTokens(); | ||
446 | }); | ||
447 | }, | ||
448 | onDeleteAccessToken: function (token) { | ||
449 | var that = this; | ||
450 | |||
451 | this.$confirm('All actions from apps using this token will fail!', 'Really delete this access token?', { confirmButtonText: 'Yes Delete', cancelButtonText: 'No' }).then(function () { | ||
452 | superagent.delete('/api/tokens/' + token).query({ access_token: localStorage.accessToken }).end(function (error, result) { | ||
453 | if (error && !result) return that.$message.error(error.message); | ||
454 | |||
455 | that.refreshAccessTokens(); | ||
456 | }); | ||
457 | }).catch(function () {}); | ||
458 | |||
459 | }, | ||
418 | prettyDate: function (row, column, cellValue, index) { | 460 | prettyDate: function (row, column, cellValue, index) { |
419 | var date = new Date(cellValue), | 461 | var date = new Date(cellValue), |
420 | diff = (((new Date()).getTime() - date.getTime()) / 1000), | 462 | diff = (((new Date()).getTime() - date.getTime()) / 1000), |