Skip to content

Commit

Permalink
Maintenance: Added new way of form field change event registration wi…
Browse files Browse the repository at this point in the history
…thout usage of generic change form event.
  • Loading branch information
dominikklein committed Apr 17, 2024
1 parent b7dd40c commit 3744cfd
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 61 deletions.
Expand Up @@ -20,7 +20,7 @@ import type {
export const useEmailInboundForm = () => {
const formEmailInbound: ShallowRef<FormRef | undefined> = shallowRef()

const { values, updateFieldValues, formSetErrors } =
const { values, updateFieldValues, formSetErrors, onChangedField } =
useForm<EmailInboundData>(formEmailInbound)

const metaInformationInbound = ref<Maybe<EmailInboundMetaInformation>>(null)
Expand Down Expand Up @@ -66,31 +66,26 @@ export const useEmailInboundForm = () => {
port: {},
})

const emailInboundFormOnChanged = (
fieldName: string,
newValue: FormFieldValue,
) => {
if (fieldName === 'ssl') {
const disabled = Boolean(newValue === 'off')
emailInboundFormChangeFields.sslVerify = {
disabled,
}
onChangedField('ssl', (newValue: FormFieldValue) => {
const disabled = Boolean(newValue === 'off')
emailInboundFormChangeFields.sslVerify = {
disabled,
}

updateFieldValues({
sslVerify: !disabled,
})
updateFieldValues({
sslVerify: !disabled,
})

if (newValue === 'off') {
emailInboundFormChangeFields.port = {
value: 143,
}
} else if (newValue === 'ssl') {
emailInboundFormChangeFields.port = {
value: 993,
}
if (newValue === 'off') {
emailInboundFormChangeFields.port = {
value: 143,
}
} else if (newValue === 'ssl') {
emailInboundFormChangeFields.port = {
value: 993,
}
}
}
})

const emailInboundSchema = [
{
Expand Down Expand Up @@ -214,7 +209,6 @@ export const useEmailInboundForm = () => {
formEmailInboundSetErrors: formSetErrors,
metaInformationInbound,
emailInboundFormChangeFields,
emailInboundFormOnChanged,
updateMetaInformationInbound,
}
}
Expand Up @@ -3,19 +3,15 @@
import type { ShallowRef } from 'vue'
import { shallowRef, reactive } from 'vue'

import type {
FormFieldValue,
FormRef,
FormSchemaField,
} from '#shared/components/Form/types.ts'
import type { FormRef, FormSchemaField } from '#shared/components/Form/types.ts'
import { useForm } from '#shared/components/Form/useForm.ts'

import type { EmailOutboundData } from '../types/email-inbound-outbound.ts'

export const useEmailOutboundForm = () => {
const formEmailOutbound: ShallowRef<FormRef | undefined> = shallowRef()

const { updateFieldValues, values, formSetErrors } =
const { updateFieldValues, values, formSetErrors, onChangedField } =
useForm<EmailOutboundData>(formEmailOutbound)

const emailOutboundFormChangeFields = reactive<
Expand All @@ -24,24 +20,19 @@ export const useEmailOutboundForm = () => {
sslVerify: {},
})

const emailOutboundFormOnChanged = (
fieldName: string,
newValue: FormFieldValue,
) => {
if (fieldName === 'port') {
const disabled = Boolean(
newValue && !(newValue === '465' || newValue === '587'),
)
onChangedField('port', (newValue) => {
const disabled = Boolean(
newValue && !(newValue === '465' || newValue === '587'),
)

emailOutboundFormChangeFields.sslVerify = {
disabled,
}

updateFieldValues({
sslVerify: !disabled,
})
emailOutboundFormChangeFields.sslVerify = {
disabled,
}
}

updateFieldValues({
sslVerify: !disabled,
})
})

const emailOutboundSchema = [
{
Expand Down Expand Up @@ -137,7 +128,6 @@ export const useEmailOutboundForm = () => {
return {
formEmailOutbound,
emailOutboundSchema,
emailOutboundFormOnChanged,
emailOutboundFormChangeFields,
updateEmailOutboundFieldValues: updateFieldValues,
formEmailOutboundSetErrors: formSetErrors,
Expand Down
Expand Up @@ -77,11 +77,11 @@ const { configureSystemImportSource } = useImportSourceConfiguration(
EnumSystemImportSource.Otrs,
)
const { updateFieldValues } = useForm(form)
const { updateFieldValues, onChangedField } = useForm(form)
const formChangeFields = reactive<Record<string, Partial<FormSchemaField>>>({})
const onChangedURL = (fieldName: string, newValue: FormFieldValue) => {
if (fieldName === 'url' && newValue && typeof newValue === 'string') {
onChangedField('url', (newValue: FormFieldValue) => {
if (newValue && typeof newValue === 'string') {
const disabled = newValue.startsWith('http://')
formChangeFields.sslVerify = {
Expand All @@ -92,7 +92,7 @@ const onChangedURL = (fieldName: string, newValue: FormFieldValue) => {
sslVerify: !disabled,
})
}
}
})
</script>

<template>
Expand All @@ -116,7 +116,6 @@ const onChangedURL = (fieldName: string, newValue: FormFieldValue) => {
:handlers="[useSSLVerificationWarningHandler()]"
:schema="formSchema"
:change-fields="formChangeFields"
@changed="onChangedURL"
@submit="
configureSystemImportSource(
$event as FormSubmitData<ImportSourceConfigurationOtrsData>,
Expand Down
Expand Up @@ -48,7 +48,6 @@ const {
formEmailInboundValues,
formEmailInboundSetErrors,
updateEmailInboundFieldValues,
emailInboundFormOnChanged,
metaInformationInbound,
emailInboundFormChangeFields,
updateMetaInformationInbound,
Expand All @@ -67,7 +66,6 @@ const {
formEmailOutboundSetErrors,
updateEmailOutboundFieldValues,
emailOutboundFormChangeFields,
emailOutboundFormOnChanged,
} = useEmailOutboundForm()
const {
Expand Down Expand Up @@ -213,7 +211,6 @@ const emailConfigurationCheck = computed(() => {
"
:schema="emailInboundSchema"
:change-fields="emailInboundFormChangeFields"
@changed="emailInboundFormOnChanged"
@submit="
validateEmailInbound($event as FormSubmitData<EmailInboundData>)
"
Expand Down Expand Up @@ -247,7 +244,6 @@ const emailConfigurationCheck = computed(() => {
"
:schema="emailOutboundSchema"
:change-fields="emailOutboundFormChangeFields"
@changed="emailOutboundFormOnChanged"
@submit="
validateEmailOutbound($event as FormSubmitData<EmailOutboundData>)
"
Expand Down
Expand Up @@ -33,7 +33,6 @@ const {
formEmailOutbound,
emailOutboundSchema,
emailOutboundFormChangeFields,
emailOutboundFormOnChanged,
} = useEmailOutboundForm()
const emailNotificationSchema = [
Expand Down Expand Up @@ -105,7 +104,6 @@ const probeEmailNotification = async (data: EmailNotificationData) => {
:schema="emailNotificationSchema"
:handlers="[useSSLVerificationWarningHandler()]"
:change-fields="emailOutboundFormChangeFields"
@changed="emailOutboundFormOnChanged"
@submit="
probeEmailNotification($event as FormSubmitData<EmailNotificationData>)
"
Expand Down
Expand Up @@ -62,7 +62,6 @@ const ticketData = computed(() => getTicketData(organization.value))
<CommonOrganizationAvatar
:entity="organization as AvatarOrganization"
size="xl"
personal
/>
</div>
<div class="mt-2 text-xl font-bold">
Expand Down
15 changes: 13 additions & 2 deletions app/frontend/shared/components/Form/Form.vue
Expand Up @@ -57,7 +57,11 @@ import { getFirstFocusableElement } from '#shared/utils/getFocusableElements.ts'
import { parseGraphqlId } from '#shared/graphql/utils.ts'
import { useFormUpdaterQuery } from './graphql/queries/formUpdater.api.ts'
import { FormHandlerExecution, FormValidationVisibility } from './types.ts'
import { getNodeByName as getFormkitFieldNode, setErrors } from './utils.ts'
import {
getNodeByName as getFormkitFieldNode,
getNodeId,
setErrors,
} from './utils.ts'
import { getFormClasses } from './initializeFormClasses.ts'
import type {
ChangedField,
Expand Down Expand Up @@ -874,12 +878,19 @@ const changedInputValueHandling = (inputNode: FormKitNode) => {
oldValue,
})
}
emit('changed', node.name, newValue, oldValue)
formNode.value?.emit(`changed:${node.name}`, {
newValue,
oldValue,
fieldNode: node,
})
executeFormHandler(FormHandlerExecution.FieldChange, values.value, {
name: node.name,
newValue,
oldValue,
})
previousValues.set(node, cloneDeep(newValue))
updaterChangedFields.delete(node.name)
})
Expand Down Expand Up @@ -909,7 +920,7 @@ const buildStaticSchema = () => {
const buildFormKitField = (
field: FormSchemaField,
): FormKitSchemaComponent => {
const fieldId = field.id || `${field.name}-${formId}`
const fieldId = field.id || getNodeId(formId, field.name)
const plugins = [changedInputValueHandling]
Expand Down
24 changes: 23 additions & 1 deletion app/frontend/shared/components/Form/__tests__/useForm.spec.ts
@@ -1,8 +1,9 @@
// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/

import { createMessage, getNode, type FormKitNode } from '@formkit/core'

import Form from '#shared/components/Form/Form.vue'
import { useForm } from '#shared/components/Form/useForm.ts'
import { createMessage, getNode, type FormKitNode } from '@formkit/core'
import { renderComponent } from '#tests/support/components/index.ts'
import { waitForNextTick } from '#tests/support/utils.ts'
import type { FormRef, FormValues } from '../types.ts'
Expand All @@ -19,6 +20,7 @@ const schema = [
type: 'text',
name: 'title',
label: 'Title',
delay: 20, // Add default delay to simulate live situation.
},
{
type: 'textarea',
Expand Down Expand Up @@ -228,4 +230,24 @@ describe('submitting form rules', () => {
// or manually called "resetForm"
expect(canSubmit.value).toBeFalsy()
})

it('can register on change event of singlem field', async () => {
const onChangedFieldCallbackSpy = vi.fn()

const { view, utils } = renderForm()
const { form, onChangedField } = utils

// Register callback on changed title field.
onChangedField('title', onChangedFieldCallbackSpy)

await view.events.debounced(() =>
view.events.type(view.getByLabelText('Title'), 'Some title'),
)

expect(onChangedFieldCallbackSpy).toHaveBeenCalledWith(
'Some title',
'',
form.value?.getNodeByName('title'),
)
})
})
24 changes: 24 additions & 0 deletions app/frontend/shared/components/Form/useForm.ts
Expand Up @@ -88,6 +88,29 @@ export const useForm = <T = FormValues>(formRef?: Ref<FormRef | undefined>) => {
})
}

const onChangedField = (
name: string,
callback: (
newValue: FormFieldValue,
oldValue: FormFieldValue,
node: FormKitNode,
) => void,
) => {
const registerChangeEvent = (node: FormKitNode) => {
node.on(`changed:${name}`, ({ payload }) => {
callback(payload.newValue, payload.oldValue, payload.fieldNode)
})
}

if (node.value) {
registerChangeEvent(node.value)
} else {
waitForFormSettled().then((node) => {
registerChangeEvent(node)
})
}
}

const updateFieldValues = (fieldValues: Record<string, FormFieldValue>) => {
const changedFieldValues: Record<
string,
Expand Down Expand Up @@ -133,5 +156,6 @@ export const useForm = <T = FormValues>(formRef?: Ref<FormRef | undefined>) => {
formSubmit,
waitForFormSettled,
updateFieldValues,
onChangedField,
}
}

0 comments on commit 3744cfd

Please sign in to comment.