useTicketEdit.ts 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { isEqual } from 'lodash-es'
  3. import { computed, ref, watch } from 'vue'
  4. import { populateEditorNewLines } from '#shared/components/Form/fields/FieldEditor/utils.ts'
  5. import type {
  6. FormValues,
  7. FormRef,
  8. FormSubmitData,
  9. } from '#shared/components/Form/types.ts'
  10. import { getNodeByName } from '#shared/components/Form/utils.ts'
  11. import { useObjectAttributeFormData } from '#shared/entities/object-attributes/composables/useObjectAttributeFormData.ts'
  12. import { useObjectAttributes } from '#shared/entities/object-attributes/composables/useObjectAttributes.ts'
  13. import { useTicketUpdateMutation } from '#shared/entities/ticket/graphql/mutations/update.api.ts'
  14. import type { TicketById } from '#shared/entities/ticket/types.ts'
  15. import type { TicketArticleFormValues } from '#shared/entities/ticket-article/action/plugins/types.ts'
  16. import type {
  17. TicketUpdateInput,
  18. TicketUpdateMetaInput,
  19. } from '#shared/graphql/types.ts'
  20. import { EnumObjectManagerObjects } from '#shared/graphql/types.ts'
  21. import { MutationHandler } from '#shared/server/apollo/handler/index.ts'
  22. import type { GraphQLHandlerError } from '#shared/types/error.ts'
  23. import type { PartialRequired } from '#shared/types/utils.ts'
  24. import { convertFilesToAttachmentInput } from '#shared/utils/files.ts'
  25. import type { ComputedRef, ShallowRef } from 'vue'
  26. type TicketArticleReceivedFormValues = PartialRequired<
  27. TicketArticleFormValues,
  28. // form always has these values
  29. 'articleType' | 'body' | 'internal'
  30. >
  31. const TICKET_FORM_RELEVANT_KEYS = [
  32. 'id',
  33. 'group',
  34. 'owner',
  35. 'state',
  36. 'pending_time',
  37. 'priority',
  38. 'customer',
  39. 'organization',
  40. 'objectAttributeValues',
  41. ]
  42. export const useTicketEdit = (
  43. ticket: ComputedRef<TicketById | undefined>,
  44. form: ShallowRef<FormRef | undefined>,
  45. errorCallback?: (error: GraphQLHandlerError) => boolean,
  46. ) => {
  47. const initialTicketValue = ref<FormValues>()
  48. const mutationUpdate = new MutationHandler(useTicketUpdateMutation(), {
  49. errorCallback,
  50. errorNotificationMessage: __('Ticket update failed.'),
  51. })
  52. const ticketFormRelatedData = computed<Partial<TicketById>>(
  53. (currentTicketFormRelatedData) => {
  54. if (!ticket.value) return {}
  55. const newTicketFormRelatedData = (
  56. TICKET_FORM_RELEVANT_KEYS as Array<keyof TicketById>
  57. ).reduce<Partial<TicketById>>((relevantData, key) => {
  58. if (!ticket.value || !(key in ticket.value)) return relevantData
  59. relevantData[key] = ticket.value[key]
  60. return relevantData
  61. }, {})
  62. if (
  63. currentTicketFormRelatedData &&
  64. isEqual(newTicketFormRelatedData, currentTicketFormRelatedData)
  65. ) {
  66. return currentTicketFormRelatedData
  67. }
  68. return newTicketFormRelatedData
  69. },
  70. )
  71. watch(
  72. ticketFormRelatedData,
  73. () => {
  74. if (!ticket.value) {
  75. return
  76. }
  77. const { internalId: ownerInternalId } = ticket.value.owner
  78. initialTicketValue.value = {
  79. id: ticket.value.id,
  80. owner_id: ownerInternalId === 1 ? null : ownerInternalId,
  81. isDefaultFollowUpStateSet: undefined, // the default value for reset situations.
  82. }
  83. if (!form.value?.formInitialSettled) return
  84. form.value?.resetForm(
  85. {
  86. values: initialTicketValue.value,
  87. object: ticket.value,
  88. },
  89. {
  90. resetDirty: false,
  91. },
  92. )
  93. },
  94. { immediate: true },
  95. )
  96. const isTicketFormGroupValid = computed(() => {
  97. const ticketGroup = form.value?.formNode?.at('ticket')
  98. return !!ticketGroup?.context?.state.valid
  99. })
  100. const { attributesLookup: ticketObjectAttributesLookup } =
  101. useObjectAttributes(EnumObjectManagerObjects.Ticket)
  102. const processArticle = (
  103. formId: string,
  104. article: TicketArticleReceivedFormValues | undefined,
  105. ) => {
  106. if (!article) return null
  107. const contentType =
  108. getNodeByName(formId, 'body')?.context?.contentType || 'text/html'
  109. if (contentType === 'text/html') {
  110. article.body = populateEditorNewLines(article.body)
  111. }
  112. return {
  113. type: article.articleType,
  114. body: article.body,
  115. internal: article.internal,
  116. cc: article.cc,
  117. to: article.to,
  118. subject: article.subject,
  119. subtype: article.subtype,
  120. inReplyTo: article.inReplyTo,
  121. contentType,
  122. attachments: convertFilesToAttachmentInput(formId, article.attachments),
  123. security: article.security,
  124. timeUnit: article.timeUnit,
  125. accountedTimeTypeId: article.accountedTimeTypeId,
  126. }
  127. }
  128. const editTicket = async (
  129. formData: FormSubmitData,
  130. meta?: TicketUpdateMetaInput,
  131. ) => {
  132. if (!ticket.value || !form.value) return undefined
  133. if (!formData.owner_id) {
  134. formData.owner_id = 1
  135. }
  136. const { internalObjectAttributeValues, additionalObjectAttributeValues } =
  137. useObjectAttributeFormData(ticketObjectAttributesLookup.value, formData)
  138. const formArticle = formData.article as
  139. | TicketArticleReceivedFormValues
  140. | undefined
  141. const article = processArticle(form.value.formId, formArticle)
  142. const ticketMeta = meta || {}
  143. return mutationUpdate.send({
  144. ticketId: ticket.value.id,
  145. input: {
  146. ...internalObjectAttributeValues,
  147. objectAttributeValues: additionalObjectAttributeValues,
  148. article,
  149. } as TicketUpdateInput,
  150. meta: ticketMeta,
  151. })
  152. }
  153. return {
  154. initialTicketValue,
  155. isTicketFormGroupValid,
  156. editTicket,
  157. }
  158. }