Skip to content

Commit

Permalink
Maintenance: Desktop view - Improve form reset handling for different…
Browse files Browse the repository at this point in the history
… situations (fixes also zammad#5356).
  • Loading branch information
dominikklein committed Oct 1, 2024
1 parent 5d8c8c2 commit 004cffd
Show file tree
Hide file tree
Showing 14 changed files with 290 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ watch(formInitialValues, (newValues) => {
// No reset needed when the form has already the correct state.
if (isEqual(values.value, newValues) && !isDirty.value) return

formReset(newValues)
formReset({ values: newValues })
})

const { notify } = useNotifications()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ watch(initialFormValues, (newValues) => {
// No reset needed when the form has already the correct state.
if (isEqual(values.value, newValues) && !isDirty.value) return

formReset(newValues)
formReset({ values: newValues })
})

onChangedField('file', (fileName) => {
Expand Down Expand Up @@ -151,7 +151,9 @@ const resetFormToDefaults = (
personalSettings: UserData['personalSettings'],
) => {
form.value?.resetForm({
matrix: personalSettings?.notificationConfig?.matrix || {},
values: {
matrix: personalSettings?.notificationConfig?.matrix || {},
},
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ watch(initialFormValues, (newValues) => {
// No reset needed when the form has already the correct state.
if (isEqual(values.value, newValues) && !isDirty.value) return

formReset(newValues, user.value!)
formReset({ values: newValues, object: user.value! })
})

const buildFormChangesHash = (enabled: boolean) => {
Expand Down
20 changes: 15 additions & 5 deletions app/frontend/apps/desktop/pages/ticket/views/TicketDetailView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import {
useNotifications,
} from '#shared/components/CommonNotifications/index.ts'
import Form from '#shared/components/Form/Form.vue'
import type { FormSubmitData } from '#shared/components/Form/types.ts'
import type {
FormSubmitData,
FormValues,
} from '#shared/components/Form/types.ts'
import { useForm } from '#shared/components/Form/useForm.ts'
import { setErrors } from '#shared/components/Form/utils.ts'
import { useConfirmation } from '#shared/composables/useConfirmation.ts'
Expand Down Expand Up @@ -459,10 +462,17 @@ const submitEditTicket = async (
})

// Reset article form after ticket update and reset form.
return () => {
newTicketArticlePresent.value = false

formReset({ ticket: undefined })
newTicketArticlePresent.value = false

return {
reset: (
values: FormSubmitData<TicketUpdateFormData>,
formNodeValues: FormValues,
) => {
nextTick(() => {
formReset({ values: { ticket: formNodeValues.ticket } })
})
},
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { mockPermissions } from '#tests/support/mock-permissions.ts'
import { mockUserCurrent } from '#tests/support/mock-userCurrent.ts'
import { nullableMock, waitUntil } from '#tests/support/utils.ts'

import { TicketUpdateDocument } from '#shared/entities/ticket/graphql/mutations/update.api.ts'
import { TicketArticlesDocument } from '#shared/entities/ticket/graphql/queries/ticket/articles.api.ts'
import { TicketArticleUpdatesDocument } from '#shared/entities/ticket/graphql/subscriptions/ticketArticlesUpdates.api.ts'
import { TicketUpdatesDocument } from '#shared/entities/ticket/graphql/subscriptions/ticketUpdates.api.ts'
Expand Down Expand Up @@ -943,6 +944,55 @@ describe('ticket add/edit reply article', () => {

expect(form?.find('body', 'name')?.value).toBe('Testing')
})

it('save one reply and cancel second reply (save button should not be visible)', async () => {
const { waitUntilTicketLoaded, ticket } = mockTicketDetailViewGql({
mockFrontendObjectAttributes: true,
})

const view = await visitView('/tickets/1')

await waitUntilTicketLoaded()

await view.events.click(view.getByRole('button', { name: 'Add reply' }))

expect(
await view.findByRole('dialog', { name: 'Add reply' }),
).toBeInTheDocument()

await view.events.type(view.getByLabelText('Text'), 'Testing')

expect(
await view.findByRole('button', { name: 'Save' }),
).toBeInTheDocument()

mockGraphQLApi(TicketUpdateDocument).willResolve({
ticketUpdate: {
ticket,
errors: null,
__typename: 'TicketUpdatePayload',
},
})

await view.events.click(view.getByRole('button', { name: 'Save' }))

expect(
await view.findByRole('button', { name: 'Add reply' }),
).toBeInTheDocument()

await view.events.click(view.getByRole('button', { name: 'Add reply' }))

expect(
await view.findByRole('dialog', { name: 'Add reply' }),
).toBeInTheDocument()

await view.events.click(view.getByRole('button', { name: 'Cancel' }))

expect(
await view.findByRole('button', { name: 'Add reply' }),
).toBeInTheDocument()
expect(view.queryByRole('button', { name: 'Save' })).not.toBeInTheDocument()
})
})

it('correctly redirects from ticket hash-based routes', async () => {
Expand Down
27 changes: 18 additions & 9 deletions app/frontend/apps/mobile/pages/ticket/views/TicketDetailView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<script setup lang="ts">
import { cloneDeep, noop } from 'lodash-es'
import { computed, provide, ref, reactive, toRef } from 'vue'
import { computed, provide, ref, reactive, toRef, nextTick } from 'vue'
import {
onBeforeRouteLeave,
onBeforeRouteUpdate,
Expand All @@ -16,7 +16,10 @@ import {
useNotifications,
} from '#shared/components/CommonNotifications/index.ts'
import Form from '#shared/components/Form/Form.vue'
import type { FormSubmitData } from '#shared/components/Form/types.ts'
import type {
FormSubmitData,
FormValues,
} from '#shared/components/Form/types.ts'
import { useForm } from '#shared/components/Form/useForm.ts'
import { useConfirmation } from '#shared/composables/useConfirmation.ts'
import { useOnlineNotificationSeen } from '#shared/composables/useOnlineNotificationSeen.ts'
Expand Down Expand Up @@ -172,13 +175,19 @@ const saveTicketForm = async (
})

// Reset article form after ticket update and reset form.
return () => {
newTicketArticlePresent.value = false
closeArticleReplyDialog().then(() => {
// after the dialog is closed, form changes value from reseted { ticket, article } to { ticket }
// which makes it dirty, so we reset it again to be just { ticket }
formReset({ ticket: formData.ticket })
})
newTicketArticlePresent.value = false

return {
reset: (
values: FormSubmitData<TicketUpdateFormData>,
formNodeValues: FormValues,
) => {
nextTick(() => {
closeArticleReplyDialog().then(() => {
formReset({ values: { ticket: formNodeValues.ticket } })
})
})
},
}
}
} catch (errors) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,14 @@ const discardTicketEditDialog = async () => {
if (!confirmed) return

form.value?.resetForm(
initialFormTicketValue.value,
ticket.value,
{ resetDirty: true },
ticketFormGroupNode.value,
{
values: initialFormTicketValue.value,
object: ticket.value,
},
{
resetDirty: true,
groupNode: ticketFormGroupNode.value,
},
)
}

Expand Down
Loading

0 comments on commit 004cffd

Please sign in to comment.