feat(frontend): token revokation and creation ✅
This commit is contained in:
@@ -2,27 +2,38 @@
|
||||
<v-list-item>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title>
|
||||
<v-chip small outlined class="mr-2">{{ token.lastChars }}</v-chip>
|
||||
<v-chip small class="mr-2">{{ token.id }}</v-chip>
|
||||
<b>{{ token.name }}</b>
|
||||
</v-list-item-title>
|
||||
<v-list-item-subtitle>
|
||||
Created:
|
||||
{{ token.createdAt | dateParse() | dateFormat("DD MMM YY") }} (
|
||||
<timeago :datetime="token.createdAt"></timeago>
|
||||
) Last Used:
|
||||
{{ token.lastUsed | dateParse() | dateFormat("DD MMM YY") }} (
|
||||
<timeago :datetime="token.lastUsed"></timeago>
|
||||
)
|
||||
<v-list-item-subtitle class="caption">
|
||||
<b>Created:</b>
|
||||
{{ token.createdAt | dateParse() | dateFormat("DD MMM YYYY") }}
|
||||
<b>Last Used:</b>
|
||||
{{ token.lastUsed | dateParse() | dateFormat("DD MMM YYYY") }}
|
||||
</v-list-item-subtitle>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action>
|
||||
<v-btn small icon>
|
||||
<v-btn small icon @click="showRevokeConfirm = true">
|
||||
<v-icon color="error">mdi-delete</v-icon>
|
||||
</v-btn>
|
||||
</v-list-item-action>
|
||||
<v-dialog v-model="showRevokeConfirm" width="500">
|
||||
<v-card class="pa-3">
|
||||
<v-card-title>Are you sure?</v-card-title>
|
||||
<v-card-text>
|
||||
You cannot undo this action. This will permanently delete this token.
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-btn color="error" @click="revokeToken">Delete</v-btn>
|
||||
<v-btn @click="showRevokeConfirm = false">Cancel</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
</v-list-item>
|
||||
</template>
|
||||
<script>
|
||||
import gql from "graphql-tag"
|
||||
|
||||
export default {
|
||||
components: {},
|
||||
props: {
|
||||
@@ -31,9 +42,26 @@ export default {
|
||||
default: () => {}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showRevokeConfirm: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
revokeToken() {
|
||||
// TODO
|
||||
async revokeToken() {
|
||||
try {
|
||||
await this.$apollo.mutate({
|
||||
mutation: gql`
|
||||
mutation {
|
||||
apiTokenRevoke(token: "${this.token.id}")
|
||||
}
|
||||
`
|
||||
})
|
||||
this.$emit('deleted')
|
||||
this.showRevokeConfirm = false
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,12 @@
|
||||
<v-card-title>Personal Access Tokens</v-card-title>
|
||||
<v-card-text>
|
||||
Personal Access Tokens can be used to access the Speckle API on this
|
||||
server; they function like ordinary OAuth access tokens.
|
||||
<b>Treat them like a password!</b>
|
||||
server; they function like ordinary OAuth access tokens. Use them in your
|
||||
scripts or apps!
|
||||
<b>
|
||||
Treat them like a password: do not post them anywhere where they could
|
||||
be accessed by others (e.g., public repos).
|
||||
</b>
|
||||
</v-card-text>
|
||||
<v-card-text v-if="$apollo.loading">Loading...</v-card-text>
|
||||
<v-card-text v-if="tokens">
|
||||
@@ -13,13 +17,14 @@
|
||||
v-for="token in tokens"
|
||||
:key="token.id"
|
||||
:token="token"
|
||||
@deleted="refreshList"
|
||||
/>
|
||||
</v-list>
|
||||
</v-card-text>
|
||||
<v-card-text>
|
||||
<v-btn @click="tokenDialog = true">new token</v-btn>
|
||||
<v-dialog v-model="tokenDialog" width="500">
|
||||
<token-dialog />
|
||||
<v-dialog v-model="tokenDialog" persistent width="500">
|
||||
<token-dialog @token-added="refreshList" @close="tokenDialog = false" />
|
||||
</v-dialog>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
@@ -55,6 +60,10 @@ export default {
|
||||
update: (data) => data.user.apiTokens
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
methods: {
|
||||
refreshList() {
|
||||
this.$apollo.queries.tokens.refetch()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<v-card class="pa-4" color="background2">
|
||||
<v-card-title class="subtitle-1">
|
||||
<v-card-title>
|
||||
Create a New Personal Access Token
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn text color="error" icon @click="clearAndClose"><v-icon>mdi-close</v-icon></v-btn>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-form>
|
||||
<v-form v-show="!fullTokenResult">
|
||||
<h3 class="mt-3">Token Scopes</h3>
|
||||
<p>
|
||||
It's good practice to limit the scopes of your token to the absolute
|
||||
@@ -46,8 +48,21 @@
|
||||
autofocus
|
||||
></v-text-field>
|
||||
<br />
|
||||
<v-btn>Save</v-btn>
|
||||
<v-btn @click="createToken">Save</v-btn>
|
||||
<v-btn text color="error" @click="clearAndClose">Cancel</v-btn>
|
||||
</v-form>
|
||||
<div v-show="fullTokenResult">
|
||||
<div class="text-center my-5">
|
||||
<h2 class="mb-5 font-weight-normal">Your new token:</h2>
|
||||
<code class="subtitle-1 pa-3 my-4">{{ fullTokenResult }}</code>
|
||||
</div>
|
||||
<v-alert type="info">
|
||||
<b>Note:</b>
|
||||
This is the first and last time you will be able to see the full
|
||||
token. Please copy paste it somewhere safe now.
|
||||
</v-alert>
|
||||
<v-btn block color="primary" @click="clearAndClose">Close</v-btn>
|
||||
</div>
|
||||
</v-card-text>
|
||||
</v-card>
|
||||
</template>
|
||||
@@ -83,19 +98,41 @@ export default {
|
||||
(v) => !!v || "Name is required",
|
||||
(v) => (v && v.length <= 60) || "Name must be less than 60 characters"
|
||||
],
|
||||
selectedScopes: []
|
||||
selectedScopes: [],
|
||||
fullTokenResult: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showDialog: {
|
||||
get() {
|
||||
return this.show
|
||||
},
|
||||
set(value) {
|
||||
this.$emit("input", value)
|
||||
methods: {
|
||||
clearAndClose() {
|
||||
this.fullTokenResult = null
|
||||
this.name = null
|
||||
this.selectedScopes = []
|
||||
this.$emit("close")
|
||||
},
|
||||
async createToken() {
|
||||
try {
|
||||
let res = await this.$apollo.mutate({
|
||||
mutation: gql`
|
||||
mutation($token: ApiTokenCreateInput!) {
|
||||
apiTokenCreate(token: $token)
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
token: {
|
||||
name: this.name,
|
||||
scopes: this.selectedScopes
|
||||
}
|
||||
}
|
||||
})
|
||||
this.fullTokenResult = res.data.apiTokenCreate
|
||||
this.name = null
|
||||
this.selectedScopes = []
|
||||
this.$emit("token-added")
|
||||
} catch (e) {
|
||||
// TODO: how do we catch and display errors?
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user