Skip to content

Commit

Permalink
feat(field-multiselect): setup syntax [khcp-11341] (#1885)
Browse files Browse the repository at this point in the history
Convert KMultiselect to setup syntax for [KHCP-11341](https://konghq.atlassian.net/browse/KHCP-11341).

Other fixes:
- Add testing of style classes to other entities
- add support for missing props to FieldMultiselect:
  - `id`
  - `classNames`
  - `disabled`
  - `name`
  - add `data-testid` to KPop

---------

Co-authored-by: GU Yiling <[email protected]>
  • Loading branch information
kaiarrowood and Justineo authored Jan 10, 2025
1 parent cab3896 commit df4ffbb
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 23 deletions.
29 changes: 29 additions & 0 deletions packages/core/forms/sandbox/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,31 @@ const fieldSchema = {
{ name: 'Female', value: 'female' },
],
},
// FieldSelect
{
type: 'select',
model: 'https_redirect_status_code',
label: 'HTTPS Redirect Status Code',
values: [426, 301, 302, 307, 308],
},
// FieldMultiselect
{
type: 'multiselect',
model: 'protocols',
label:'Protocols',
values: [
{ label: 'GRPC', value: 'grpc' },
{ label: 'GRPCS', value: 'grpcs' },
{ label: 'HTTP', value: 'http' },
{ label: 'HTTPS', value: 'https' },
{ label: 'TCP', value: 'tcp' },
{ label: 'TLS', value: 'tls' },
{ label: 'TLS_PASSTHROUGH', value: 'tls_passthrough' },
{ label: 'UDP', value: 'udp' },
{ label: 'WS', value: 'ws' },
{ label: 'WSS', value: 'wss' },
],
},
// FieldSwitch
{
type: 'switch',
Expand All @@ -92,6 +117,8 @@ const fieldModelDefault = ref({
is_friendly: true,
is_cute: true,
gender: 'male',
https_redirect_status_code: '',
protocols: ['http', 'https'],
})
const fieldModelModified = ref({
Expand All @@ -100,6 +127,8 @@ const fieldModelModified = ref({
is_cute: false,
gender: null,
personality: 'A little bit of a brat',
https_redirect_status_code: 307,
protocols: ['https', 'wss'],
})
</script>

Expand Down
94 changes: 71 additions & 23 deletions packages/core/forms/src/components/fields/FieldMultiselect.vue
Original file line number Diff line number Diff line change
@@ -1,41 +1,89 @@
<template>
<KMultiselect
:id="getFieldID(schema)"
v-model="inputValue"
:aria-labelledby="getLabelId(schema)"
:class="schema.fieldClasses"
data-testid="field-multiselect"
:disabled="disabled || undefined"
:items="items"
:kpop-attributes="{ 'data-testid': `${getFieldID(schema)}-items` }"
:label-attributes="{ info: schema.help }"
:model-value="value"
:name="schema.inputName"
:placeholder="schema.placeholder"
:required="schema.required || undefined"
width="100%"
@update:model-value="onUpdate"
/>
</template>

<script>
import abstractField from './abstractField'
<script lang="ts" setup>
import { computed, toRef, type PropType } from 'vue'
import type { MultiselectItem } from '@kong/kongponents'
import composables from '../../composables'
export default {
mixins: [abstractField],
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: '',
},
})
emits: ['model-updated'],
const emit = defineEmits<{
(event: 'modelUpdated', value: any, model: Record<string, any>): void
}>()
computed: {
items() {
if (this.schema.values) {
return this.schema.values
}
if (this.schema.elements?.one_of?.length) {
return this.schema.elements.one_of.map(value => ({ label: value, value }))
}
return []
},
},
const modelRef = toRef(props, 'model')
methods: {
onUpdate(value) {
this.$emit('model-updated', value, this.schema.model)
},
const { getLabelId, getFieldID, clearValidationErrors, value: inputValue } = composables.useAbstractFields({
model: modelRef,
schema: props.schema,
formOptions: props.formOptions,
emitModelUpdated: (data: { value: any, model: Record<string, any> }): void => {
emit('modelUpdated', data.value, data.model)
},
}
})
defineExpose({
clearValidationErrors,
})
const items = computed((): MultiselectItem[] => {
if (props.schema.values) {
return props.schema.values
}
if (props.schema.elements?.one_of?.length) {
return props.schema.elements.one_of.map((value: string | number | boolean) => ({ label: String(value), value: String(value) } satisfies MultiselectItem))
}
return []
})
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe('<FieldTester /> - FieldCheckbox', () => {
label: fieldLabel,
help: 'Check if the cat is cool.',
required: true,
styleClasses: 'cool-cats',
}],
}

Expand Down Expand Up @@ -43,6 +44,11 @@ describe('<FieldTester /> - FieldCheckbox', () => {
cy.get('.required').find(`.form-group-label[for="${fieldKey}"]`).should('not.exist')
}

// check style classes
if (schema.fields[0].styleClasses) {
cy.get('.form-group.field-checkbox').should('have.class', schema.fields[0].styleClasses)
}

// check help text
if (schema.fields[0].help) {
cy.get(`label[for="${fieldKey}"] .info-icon`).should('be.visible')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe('<FieldTester /> - FieldInput', () => {
id: fieldKey,
inputType: 'text',
label: fieldLabel,
styleClasses: 'awesome-cats',
help: 'The name of the cat.',
required: true,
}],
Expand Down Expand Up @@ -60,6 +61,11 @@ describe('<FieldTester /> - FieldInput', () => {
cy.get(`label[for="${fieldKey}"] .info-icon`).should('be.visible')
cy.get(`label[for="${fieldKey}"]`).should('contain.text', schema.fields[0].help)
}

// check style classes
if (schema.fields[0].styleClasses) {
cy.get('.form-group.field-input').should('have.class', schema.fields[0].styleClasses)
}
})

it('renders default state correctly - with model', () => {
Expand Down
Loading

0 comments on commit df4ffbb

Please sign in to comment.