Skip to content

Commit

Permalink
feat(vfg): convert field-text-area [khcp-11338] (#1570)
Browse files Browse the repository at this point in the history
Convert FieldTextArea to use kongponents for [KHCP-11338](https://konghq.atlassian.net/browse/KHCP-11338).
  • Loading branch information
kaiarrowood authored Aug 21, 2024
1 parent 8959349 commit 5271f1b
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 34 deletions.
39 changes: 24 additions & 15 deletions packages/core/forms/sandbox/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,29 +33,20 @@ const mutableModel = ref(model)
const fieldSchema = {
fields: [
// FieldInput
{
type: 'input',
model: 'cat_name',
id: 'cat_name',
inputType: 'text',
label: 'Cat Name',
},
// FieldCheckbox
{
type: 'checkbox',
model: 'is_friendly',
id: 'is_friendly',
label: 'Is Friendly',
},
// FieldSwitch
// FieldInput
{
type: 'switch',
model: 'is_cute',
label: 'Is Cute',
textOn: 'Cute',
textOff: 'Not Cute',
styleClasses: 'field-switch hide-label',
type: 'input',
model: 'cat_name',
id: 'cat_name',
inputType: 'text',
label: 'Cat Name',
},
// FieldRadio
{
Expand All @@ -69,6 +60,23 @@ const fieldSchema = {
{ name: 'Female', value: 'female' },
],
},
// FieldSwitch
{
type: 'switch',
model: 'is_cute',
label: 'Is Cute',
textOn: 'Cute',
textOff: 'Not Cute',
},
// FieldTextArea
{
type: 'text-area',
model: 'personality',
id: 'personality',
label: 'Personality',
placeholder: 'Describe your cat\'s personality',
rows: 4,
},
],
}
Expand All @@ -84,6 +92,7 @@ const fieldModelModified = ref({
is_friendly: false,
is_cute: false,
gender: null,
personality: 'A little bit of a brat',
})
</script>

Expand Down
6 changes: 3 additions & 3 deletions packages/core/forms/src/components/fields/FieldInput.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@
</template>

<script lang="ts" setup>
import { computed, inject, onBeforeMount, onMounted, ref, toRefs, type PropType } from 'vue'
import fecha from 'fecha'
import type { DebouncedFunc } from 'lodash-es'
import type { AutofillSlot } from '../../types'
import { AUTOFILL_SLOT } from '../../const'
import debounce from 'lodash-es/debounce'
import objGet from 'lodash-es/get'
import isFunction from 'lodash-es/isFunction'
import isNumber from 'lodash-es/isNumber'
import { computed, inject, onBeforeMount, onMounted, ref, toRefs, type PropType } from 'vue'
import composables from '../../composables'
import { AUTOFILL_SLOT } from '../../const'
import type { AutofillSlot } from '../../types'
const props = defineProps({
disabled: {
Expand Down
85 changes: 69 additions & 16 deletions packages/core/forms/src/components/fields/FieldTextArea.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<template>
<div class="field-textarea">
<textarea
<KTextArea
v-bind="$attrs"
:id="getFieldID(schema)"
v-model="value"
v-attributes="'input'"
class="form-control"
v-model="inputValue"
:class="schema.fieldClasses"
:disabled="disabled || null"
:disabled="disabled || undefined"
:help="hint || undefined"
:maxlength="schema.max"
:minlength="schema.min"
:name="schema.inputName"
Expand All @@ -20,24 +20,77 @@
<component
:is="autofillSlot"
:schema="schema"
:update="(val) => value = val"
:value="value"
:update="handleAutofill"
:value="inputValue"
/>
</div>
</template>

<script>
<script lang="ts" setup>
import { inject, toRefs, type PropType } from 'vue'
import type { AutofillSlot } from '../../types'
import { AUTOFILL_SLOT } from '../../const'
import abstractField from './abstractField'
import composables from '../../composables'
export default {
mixins: [abstractField],
inject: {
autofillSlot: {
from: AUTOFILL_SLOT,
default: undefined,
},
const props = defineProps({
disabled: {
type: Boolean,
default: false,
},
formOptions: {
type: Object as PropType<Record<string, any>>,
default: () => undefined,
},
model: {
type: Object as PropType<Record<string, any>>,
default: () => undefined,
},
schema: {
type: Object as PropType<Record<string, any>>,
required: true,
},
vfg: {
type: Object,
required: true,
},
/**
* TODO: stronger type
* TODO: pass this down to KInput error and errorMessage
*/
errors: {
type: Array,
default: () => [],
},
hint: {
type: String,
default: '',
},
})
const emit = defineEmits<{
(event: 'modelUpdated', value: any, model: Record<string, any>): void
}>()
const propsRefs = toRefs(props)
const autofillSlot = inject<AutofillSlot | undefined>(AUTOFILL_SLOT, undefined)
const { updateModelValue, getFieldID, clearValidationErrors, value: inputValue } = composables.useAbstractFields({
model: propsRefs.model,
schema: props.schema,
formOptions: props.formOptions,
emitModelUpdated: (data: { value: any, model: Record<string, any> }): void => {
emit('modelUpdated', data.value, data.model)
},
})
defineExpose({
clearValidationErrors,
})
const handleAutofill = (value: string) => {
inputValue.value = value
updateModelValue(value, value)
}
</script>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import type { FormSchema } from '../../../types'
import FieldTester from '../../../../sandbox/FieldTester.vue'

describe('<FieldTester /> - FieldTextArea', () => {
const fieldKey = 'personality'
const fieldLabel = 'Personality'
const fieldValue = 'The cutest and smartest cat in the world.'
const schema: FormSchema = {
fields: [{
type: 'text-area',
model: fieldKey,
id: fieldKey,
label: fieldLabel,
}],
}

it('renders default state correctly - without model', () => {
cy.mount(FieldTester, {
props: {
schema,
},
})

cy.get('.field-tester-container').should('exist')

// check VFG input value
cy.get(`#${fieldKey}`).should('be.visible')
cy.get(`#${fieldKey}`).should('have.value', '')

// initial model is empty after load
cy.getTestId(`field-tester-form-model-${fieldKey}-value`).should('not.exist')

// check VFG label is set correctly
cy.get(`.form-group-label[for="${fieldKey}"]`).should('be.visible')
cy.get(`.form-group-label[for="${fieldKey}"]`).should('contain.text', fieldLabel)
})

it('renders default state correctly - with model', () => {
cy.mount(FieldTester, {
props: {
schema,
model: {
[fieldKey]: fieldValue,
},
},
})

cy.get('.field-tester-container').should('exist')

// check VFG input value
cy.get(`#${fieldKey}`).should('be.visible')
cy.get(`#${fieldKey}`).should('have.value', fieldValue)

// check field test form model matches
cy.getTestId(`field-tester-form-model-${fieldKey}-value`).should('be.visible')
cy.getTestId(`field-tester-form-model-${fieldKey}-value`).should('contain.text', fieldValue)
})

it('handles input changes', () => {
const editText = ' But also a little devil.'
cy.mount(FieldTester, {
props: {
schema,
model: {
[fieldKey]: fieldValue,
},
},
})

cy.get('.field-tester-container').should('exist')

// edit the input value
cy.get(`#${fieldKey}`).should('be.visible')
cy.get(`#${fieldKey}`).type(editText)

// check VFG input value
cy.get(`#${fieldKey}`).should('have.value', fieldValue + editText)
// check field test form model
cy.getTestId(`field-tester-form-model-${fieldKey}-value`).should('contain.text', fieldValue + editText)
})

it('handles programmatic input changes', () => {
const updatedFieldValue = 'The cutest and smartest cat in the world. But also a little devil.'

cy.mount(FieldTester, {
props: {
schema,
model: {
[fieldKey]: fieldValue,
},
modifiedModel: {
[fieldKey]: updatedFieldValue,
},
},
})

cy.get('.field-tester-container').should('exist')

// initial value loaded
cy.getTestId(`field-tester-form-model-${fieldKey}-value`).should('be.visible')
cy.getTestId(`field-tester-form-model-${fieldKey}-value`).should('contain.text', fieldValue)

// programmatic update
cy.getTestId('tester-update-button').should('be.visible')
cy.getTestId('tester-update-button').click()

// check VFG input value
cy.get(`#${fieldKey}`).should('have.value', updatedFieldValue)
// check field test form model also matches
cy.getTestId(`field-tester-form-model-${fieldKey}-value`).should('contain.text', updatedFieldValue)
})
})

0 comments on commit 5271f1b

Please sign in to comment.