Implement validation
This commit is contained in:
@ -84,7 +84,11 @@ const sourceField = ref<HTMLSlInputElement>()
|
||||
const publicKeyField = ref<HTMLSlInputElement>()
|
||||
const clientCreateForm = ref<HTMLElement>()
|
||||
|
||||
const props = defineProps<{ client?: Client | null; errors: any[] | null }>()
|
||||
interface Props {
|
||||
client?: Client
|
||||
errors?: any[]
|
||||
}
|
||||
const props = defineProps<Props>()
|
||||
const emit = defineEmits<{
|
||||
(e: 'submit', data: ClientCreate): void
|
||||
(e: 'cancel'): void
|
||||
@ -198,61 +202,3 @@ async function submitForm() {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.client-form sl-input,
|
||||
.client-form sl-select,
|
||||
.client-form sl-checkbox {
|
||||
display: block;
|
||||
margin-bottom: var(--sl-spacing-medium);
|
||||
}
|
||||
|
||||
/* user invalid styles */
|
||||
.client-form sl-input[data-user-invalid]::part(base),
|
||||
.client-form sl-select[data-user-invalid]::part(combobox),
|
||||
.client-form sl-checkbox[data-user-invalid]::part(control) {
|
||||
border-color: var(--sl-color-danger-600);
|
||||
}
|
||||
|
||||
.client-form [data-user-invalid]::part(form-control-label),
|
||||
.client-form [data-user-invalid]::part(form-control-help-text),
|
||||
.client-form sl-checkbox[data-user-invalid]::part(label) {
|
||||
color: var(--sl-color-danger-700);
|
||||
}
|
||||
|
||||
.client-form sl-checkbox[data-user-invalid]::part(control) {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.client-form sl-input:focus-within[data-user-invalid]::part(base),
|
||||
.client-form sl-select:focus-within[data-user-invalid]::part(combobox),
|
||||
.client-form sl-checkbox:focus-within[data-user-invalid]::part(control) {
|
||||
border-color: var(--sl-color-danger-600);
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-color-danger-300);
|
||||
}
|
||||
|
||||
/* User valid styles */
|
||||
.client-form sl-input[data-user-valid]::part(base),
|
||||
.client-form sl-select[data-user-valid]::part(combobox),
|
||||
.client-form sl-checkbox[data-user-valid]::part(control) {
|
||||
border-color: var(--sl-color-success-600);
|
||||
}
|
||||
|
||||
.client-form [data-user-valid]::part(form-control-label),
|
||||
.client-form [data-user-valid]::part(form-control-help-text),
|
||||
.client-form sl-checkbox[data-user-valid]::part(label) {
|
||||
color: var(--sl-color-success-700);
|
||||
}
|
||||
|
||||
.client-form sl-checkbox[data-user-valid]::part(control) {
|
||||
background-color: var(--sl-color-success-600);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.client-form sl-input:focus-within[data-user-valid]::part(base),
|
||||
.client-form sl-select:focus-within[data-user-valid]::part(combobox),
|
||||
.client-form sl-checkbox:focus-within[data-user-valid]::part(control) {
|
||||
border-color: var(--sl-color-success-600);
|
||||
box-shadow: 0 0 0 var(--sl-focus-ring-width) var(--sl-color-success-300);
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -6,7 +6,8 @@
|
||||
autocomplete="off"
|
||||
help-text="Name of the secret"
|
||||
:value="secretName"
|
||||
@input="secretName = $event.target.value"
|
||||
@sl-input="secretName = $event.target.value"
|
||||
@input="emit('clearErrors')"
|
||||
ref="nameField"
|
||||
></sl-input>
|
||||
<template v-if="group">
|
||||
@ -59,15 +60,24 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { SecretCreate } from '@/client'
|
||||
import { ref } from 'vue'
|
||||
import { ref, watch } from 'vue'
|
||||
import { generateRandomPassword } from '@/api/password'
|
||||
import AddSecretsToClients from '@/components/secrets/AddSecretToClients.vue'
|
||||
import ClientSelectDropdown from '@/components/clients/ClientSelectDropdown.vue'
|
||||
import { setFieldValidation } from '@/api/validation'
|
||||
|
||||
const props = defineProps<{ group?: string }>()
|
||||
interface Props {
|
||||
group?: string
|
||||
errors?: any[]
|
||||
}
|
||||
|
||||
const emit = defineEmits<{ (e: 'submit', data: SecretCreate): void; (e: 'cancel'): void }>()
|
||||
const props = defineProps<Props>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'submit', data: SecretCreate): void
|
||||
(e: 'cancel'): void
|
||||
(e: 'clearErrors'): void
|
||||
}>()
|
||||
|
||||
const secretName = ref<string>()
|
||||
const createSecretForm = ref<HTMLFormElement>()
|
||||
@ -96,6 +106,10 @@ function cancelCreateSecret() {
|
||||
emit('cancel')
|
||||
}
|
||||
|
||||
function resetValidation() {
|
||||
setFieldValidation(nameField, '')
|
||||
}
|
||||
|
||||
function submitCreateSecret() {
|
||||
validateName()
|
||||
validateSecret()
|
||||
@ -117,4 +131,15 @@ function submitCreateSecret() {
|
||||
emit('submit', secretCreate)
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.errors,
|
||||
(errors) => {
|
||||
resetValidation()
|
||||
const nameErrors = errors.filter((e) => e.loc.includes('name'))
|
||||
if (nameErrors.length > 0) {
|
||||
setFieldValidation(nameField, nameErrors[0].msg)
|
||||
}
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
@ -58,6 +58,8 @@
|
||||
:group="createSecretParent"
|
||||
@submit="createSecret"
|
||||
@cancel="createSecretDrawer = false"
|
||||
:errors="createErrors"
|
||||
@clearErrors="clearCreateErrors"
|
||||
/>
|
||||
</Drawer>
|
||||
</template>
|
||||
@ -71,6 +73,8 @@ import { useAlertsStore } from '@/store/useAlertsStore'
|
||||
import { SshecretAdmin } from '@/client'
|
||||
import { SshecretObjectType } from '@/api/types'
|
||||
import { splitPath } from '@/api/paths'
|
||||
import { ValidationError } from '@/api/errors'
|
||||
import { assertSdkResponseOk } from '@/api/AssertSdkResponseOk'
|
||||
import SecretGroup from '@/components/secrets/SecretGroup.vue'
|
||||
import SecretGroupTreeItem from '@/components/secrets/SecretGroupTreeItem.vue'
|
||||
import SecretGroupTreeEntry from '@/components/secrets/SecretGroupTreeEntry.vue'
|
||||
@ -101,6 +105,8 @@ const createDrawerKey = ref(0)
|
||||
const createGroupDrawer = ref<boolean>(false)
|
||||
const createSecretDrawer = ref<boolean>(false)
|
||||
|
||||
const createErrors = ref([])
|
||||
|
||||
function cancelCreateGroup() {
|
||||
createGroupDrawer.value = false
|
||||
drawerKey.value += 1
|
||||
@ -172,7 +178,8 @@ async function createSecret(secretCreate: SecretCreate) {
|
||||
const response = await SshecretAdmin.addSecretApiV1SecretsPost({
|
||||
body: secretCreate,
|
||||
})
|
||||
if (response.status == 200) {
|
||||
try {
|
||||
assertSdkResponseOk(response)
|
||||
alerts.showAlert('Secret created', 'success')
|
||||
// We can close the drawer now.
|
||||
createSecretDrawer.value = false
|
||||
@ -185,12 +192,21 @@ async function createSecret(secretCreate: SecretCreate) {
|
||||
}
|
||||
|
||||
treeState.selectSecret(secretCreate.name)
|
||||
} else {
|
||||
console.error(response)
|
||||
alerts.showAlert('Secret creation failed', 'error')
|
||||
} catch (err) {
|
||||
if (err instanceof ValidationError) {
|
||||
createErrors.value = err.errors
|
||||
} else {
|
||||
const errorMessage = err.message ?? 'Unknown error'
|
||||
alerts.showAlert(`Error from backend: ${errorMessage}`, 'error')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearCreateErrors() {
|
||||
// Clear any errors from the create form.
|
||||
createErrors.value = []
|
||||
}
|
||||
|
||||
watch(
|
||||
() => treeState.secretGroupRevision,
|
||||
() => {
|
||||
|
||||
Reference in New Issue
Block a user