Files
speckle-server/packages/frontend-2/components/developer-settings/CreateTokenDialog.vue
T
2023-12-11 11:23:03 +02:00

131 lines
3.6 KiB
Vue

<template>
<LayoutDialog
v-model:open="isOpen"
max-width="sm"
:buttons="dialogButtons"
prevent-close-on-click-outside
>
<template #header>Create Token</template>
<form @submit="onSubmit">
<div class="flex flex-col gap-6">
<FormTextInput
v-model="name"
label="Name"
help="A name to remember this token by. For example, the name of the script or application you're planning to use it in!"
name="hookName"
:rules="[isRequired]"
show-required
show-label
type="text"
/>
<FormSelectBadges
v-model="scopes"
multiple
name="scopes"
label="Scopes"
placeholder="Choose Scopes"
help="It's good practice to limit the scopes of your token to the absolute minimum. For example, if your application or script will only read and write streams, select just those scopes."
show-required
:rules="[isItemSelected]"
show-label
:items="apiTokenScopes"
mount-menu-on-body
by="id"
/>
</div>
</form>
</LayoutDialog>
</template>
<script setup lang="ts">
import { useMutation } from '@vue/apollo-composable'
import { LayoutDialog, FormSelectBadges } from '@speckle/ui-components'
import type { TokenFormValues } from '~~/lib/developer-settings/helpers/types'
import { createAccessTokenMutation } from '~~/lib/developer-settings/graphql/mutations'
import { isItemSelected, isRequired } from '~~/lib/common/helpers/validation'
import { useForm } from 'vee-validate'
import {
convertThrowIntoFetchResult,
getFirstErrorMessage
} from '~~/lib/common/helpers/graphql'
import { useGlobalToast, ToastNotificationType } from '~~/lib/common/composables/toast'
import { useServerInfoScopes } from '~/lib/common/composables/serverInfo'
const emit = defineEmits<{
(e: 'token-created', tokenId: string): void
}>()
const { scopes: allScopes } = useServerInfoScopes()
const { mutate: createToken } = useMutation(createAccessTokenMutation)
const { triggerNotification } = useGlobalToast()
const { handleSubmit } = useForm<TokenFormValues>()
const isOpen = defineModel<boolean>('open', { required: true })
const name = ref('')
const scopes = ref<typeof apiTokenScopes.value>([])
const apiTokenScopes = computed(() => {
return Object.values(allScopes.value).map((value) => ({
id: value.name,
text: value.name
}))
})
const onSubmit = handleSubmit(async (tokenFormValues) => {
const result = await createToken({
token: {
name: name.value,
scopes: tokenFormValues.scopes.map((t) => t.id)
}
}).catch(convertThrowIntoFetchResult)
if (result?.data?.apiTokenCreate) {
isOpen.value = false
resetFormFields()
emit('token-created', result.data.apiTokenCreate)
triggerNotification({
type: ToastNotificationType.Success,
title: 'Webhook created',
description: 'The webhook has been successfully created'
})
} else {
const errorMessage = getFirstErrorMessage(result?.errors)
triggerNotification({
type: ToastNotificationType.Danger,
title: 'Failed to create token',
description: errorMessage
})
}
})
const dialogButtons = computed(() => [
{
text: 'Cancel',
props: { color: 'secondary', fullWidth: true, outline: true },
onClick: () => {
isOpen.value = false
}
},
{
text: 'Create',
props: { color: 'primary', fullWidth: true },
onClick: onSubmit
}
])
const resetFormFields = () => {
name.value = ''
scopes.value = []
}
watch(
() => isOpen.value,
(newVal) => {
if (newVal) {
resetFormFields()
}
}
)
</script>