Просмотр исходного кода

Maintenance: Desktop View - Improve translations for external integrations

Co-authored-by: Benjamin Scharf <bs@zammad.com>
Co-authored-by: Dominik Klein <dk@zammad.com>
Benjamin Scharf 3 месяцев назад
Родитель
Сommit
3f9670fe07
10 измененных файлов с 325 добавлено и 16 удалено
  1. 15 1
      app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/IssueTrackerList.vue
  2. 9 2
      app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitHub/TicketSidebarGitHub.vue
  3. 10 2
      app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitHub/__tests__/TicketSidebarGitHub.spec.ts
  4. 74 0
      app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitHub/__tests__/TicketSidebarGitHubError.spec.ts
  5. 9 2
      app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitLab/TicketSidebarGitLab.vue
  6. 76 0
      app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitLab/__tests__/TicketSidebGitLabError.spec.ts
  7. 9 2
      app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/useTicketExternalIssueTracker.ts
  8. 15 2
      app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarIdoit/TicketSidebarIdoitContent.vue
  9. 11 5
      app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarIdoit/__tests__/TicketSidebarIdoit.spec.ts
  10. 97 0
      app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarIdoit/__tests__/TicketSidebarIdoitError.spec.ts

+ 15 - 1
app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/IssueTrackerList.vue

@@ -2,7 +2,7 @@
 
 <script setup lang="ts">
 import { cloneDeep } from 'lodash-es'
-import { computed, toRef } from 'vue'
+import { computed, toRef, watch } from 'vue'
 
 import type { FormRef } from '#shared/components/Form/types.ts'
 import {
@@ -41,6 +41,10 @@ interface Props {
 
 const props = defineProps<Props>()
 
+const emit = defineEmits<{
+  error: [string | null]
+}>()
+
 const { isLoadingIssues, issueList, skipNextLinkUpdate, error } =
   useTicketExternalIssueTracker(
     props.screenType,
@@ -49,8 +53,15 @@ const { isLoadingIssues, issueList, skipNextLinkUpdate, error } =
     props.ticketId,
   )
 
+watch(error, () => {
+  emit('error', error.value)
+})
+
 const unlinkMutation = new MutationHandler(
   useTicketExternalReferencesIssueTrackerItemRemoveMutation(),
+  {
+    errorShowNotification: false,
+  },
 )
 
 const removeIssueLinkListCacheUpdate = (
@@ -188,6 +199,9 @@ const linkIssueMutation = new MutationHandler(
       })
     },
   }),
+  {
+    errorShowNotification: false,
+  },
 )
 
 const linkIssue = async (link: string) => {

+ 9 - 2
app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitHub/TicketSidebarGitHub.vue

@@ -1,7 +1,7 @@
 <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
 
 <script setup lang="ts">
-import { computed, useTemplateRef, toRef, watch, onMounted } from 'vue'
+import { computed, useTemplateRef, ref, toRef, watch, onMounted } from 'vue'
 
 import { EnumTicketExternalReferencesIssueTrackerType } from '#shared/graphql/types.ts'
 
@@ -29,6 +29,12 @@ const { hideSidebar, issueLinks, isTicketEditable, openIssuesBadge } =
 
 const issueTrackerListInstance = useTemplateRef('issue-tracker-list')
 
+const error = ref<string | null>(null)
+
+const handleError = (message: string | null) => {
+  error.value = message
+}
+
 const flyoutConfig = {
   name: 'link-github-issue',
   icon: props.sidebarPlugin.icon,
@@ -55,7 +61,7 @@ if (props.context.screenType === TicketSidebarScreenType.TicketDetailView) {
 }
 
 const actions = computed((): MenuItem[] =>
-  issueLinks.value?.length
+  issueLinks.value?.length && !error.value
     ? [
         {
           key: 'link-github-issue',
@@ -91,6 +97,7 @@ const actions = computed((): MenuItem[] =>
         :issue-links="issueLinks"
         :tracker-type="EnumTicketExternalReferencesIssueTrackerType.Github"
         :flyout-config="flyoutConfig"
+        @error="handleError"
       />
     </TicketSidebarContent>
   </TicketSidebarWrapper>

+ 10 - 2
app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitHub/__tests__/TicketSidebarGitHub.spec.ts

@@ -9,9 +9,11 @@ import { waitForNextTick } from '#tests/support/utils.ts'
 
 import { createDummyTicket } from '#shared/entities/ticket-article/__tests__/mocks/ticket.ts'
 import { EnumTicketExternalReferencesIssueTrackerItemState } from '#shared/graphql/types.ts'
+import { convertToGraphQLId } from '#shared/graphql/utils.ts'
 
 import TicketSidebarGitHub from '#desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitHub/TicketSidebarGitHub.vue'
 import { TICKET_SIDEBAR_SYMBOL } from '#desktop/pages/ticket/composables/useTicketSidebar.ts'
+import { waitForTicketExternalReferencesIssueTrackerItemAddMutationCalls } from '#desktop/pages/ticket/graphql/mutations/ticketExternalReferencesIssueTrackerItemAdd.mocks.ts'
 import { waitForTicketExternalReferencesIssueTrackerItemRemoveMutationCalls } from '#desktop/pages/ticket/graphql/mutations/ticketExternalReferencesIssueTrackerItemRemove.mocks.ts'
 import { mockTicketExternalReferencesIssueTrackerItemListQuery } from '#desktop/pages/ticket/graphql/queries/ticketExternalReferencesIssueTrackerList.mocks.ts'
 import { TicketSidebarScreenType } from '#desktop/pages/ticket/types/sidebar.ts'
@@ -196,7 +198,6 @@ describe('TicketSidebarGitHub', () => {
     ).toBeInTheDocument()
   })
 
-  // :TODO Missing field 'ticketExternalReferencesIssueTrackerItemList'
   it('links a new issue with issues present', async () => {
     const wrapper = renderGitHubSidebar()
 
@@ -226,7 +227,14 @@ describe('TicketSidebarGitHub', () => {
       wrapper.getByRole('button', { name: 'Link Issue' }),
     )
 
-    // :TODO add mutation trigger
+    const calls =
+      await waitForTicketExternalReferencesIssueTrackerItemAddMutationCalls()
+
+    expect(calls.at(-1)?.variables).toEqual({
+      issueTrackerLink: 'https://git.zammad.com/zammad/zammad/-/issues/124',
+      issueTrackerType: 'github',
+      ticketId: convertToGraphQLId('Ticket', 1),
+    })
   })
 
   it('links a new issue with no issues present', async () => {

+ 74 - 0
app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitHub/__tests__/TicketSidebarGitHubError.spec.ts

@@ -0,0 +1,74 @@
+// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
+
+import { computed } from 'vue'
+
+import renderComponent from '#tests/support/components/renderComponent.ts'
+import { mockApplicationConfig } from '#tests/support/mock-applicationConfig.ts'
+import { mockGraphQLApi } from '#tests/support/mock-graphql-api.ts'
+
+import { createDummyTicket } from '#shared/entities/ticket-article/__tests__/mocks/ticket.ts'
+import { GraphQLErrorTypes } from '#shared/types/error.ts'
+
+import githubPlugin from '#desktop/pages/ticket/components/TicketSidebar/plugins/github.ts'
+import TicketSidebarGitHub from '#desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitHub/TicketSidebarGitHub.vue'
+import { TicketExternalReferencesIssueTrackerItemListDocument } from '#desktop/pages/ticket/graphql/queries/ticketExternalReferencesIssueTrackerList.api.ts'
+import { TicketSidebarScreenType } from '#desktop/pages/ticket/types/sidebar.ts'
+
+describe('errors', () => {
+  it('shows an generic error message if query fails due failure of GitLab api', async () => {
+    mockApplicationConfig({
+      github_integration: true,
+    })
+
+    mockGraphQLApi(
+      TicketExternalReferencesIssueTrackerItemListDocument,
+    ).willFailWithError([
+      {
+        message:
+          'GitHub request failed. Please have a look at the log file for details',
+        extensions: {
+          type: GraphQLErrorTypes.UnknownError,
+        },
+      },
+    ])
+
+    const wrapper = renderComponent(TicketSidebarGitHub, {
+      props: {
+        sidebar: 'github',
+        sidebarPlugin: githubPlugin,
+        selected: true,
+        context: {
+          screenType: TicketSidebarScreenType.TicketDetailView,
+          formValues: {},
+          toggleCollapse: () => {},
+          isCollapsed: false,
+          ticket: computed(() =>
+            createDummyTicket({
+              externalReferences: {
+                github: [
+                  // 'https://github.com/zammad/zammad/issues/54',
+                  // 'https://github.com/zammad/zammad/issues/55',
+                ],
+              },
+            }),
+          ),
+          isTicketEditable: true,
+        },
+      },
+      global: {
+        stubs: {
+          teleport: true,
+        },
+      },
+      flyout: true,
+    })
+
+    expect(await wrapper.findByRole('alert')).toHaveTextContent(
+      'Error fetching information from GitHub. Please contact your administrator.',
+    )
+
+    expect(
+      wrapper.queryByRole('button', { name: 'Action menu button' }),
+    ).not.toBeInTheDocument()
+  })
+})

+ 9 - 2
app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitLab/TicketSidebarGitLab.vue

@@ -1,7 +1,7 @@
 <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
 
 <script setup lang="ts">
-import { computed, onMounted, toRef, useTemplateRef, watch } from 'vue'
+import { computed, onMounted, ref, toRef, useTemplateRef, watch } from 'vue'
 
 import { EnumTicketExternalReferencesIssueTrackerType } from '#shared/graphql/types.ts'
 
@@ -29,6 +29,12 @@ const { hideSidebar, issueLinks, isTicketEditable, openIssuesBadge } =
 
 const issueTrackerListInstance = useTemplateRef('issue-tracker-list')
 
+const error = ref<string | null>(null)
+
+const handleError = (message: string | null) => {
+  error.value = message
+}
+
 const flyoutConfig = {
   name: 'link-gitlab-issue',
   icon: props.sidebarPlugin.icon,
@@ -55,7 +61,7 @@ if (props.context.screenType === TicketSidebarScreenType.TicketDetailView) {
 }
 
 const actions = computed((): MenuItem[] =>
-  issueLinks.value?.length
+  issueLinks.value?.length && !error.value
     ? [
         {
           key: 'link-gilab-issue',
@@ -91,6 +97,7 @@ const actions = computed((): MenuItem[] =>
         :issue-links="issueLinks"
         :tracker-type="EnumTicketExternalReferencesIssueTrackerType.Gitlab"
         :flyout-config="flyoutConfig"
+        @error="handleError"
       />
     </TicketSidebarContent>
   </TicketSidebarWrapper>

+ 76 - 0
app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitLab/__tests__/TicketSidebGitLabError.spec.ts

@@ -0,0 +1,76 @@
+// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
+
+import { computed } from 'vue'
+
+import renderComponent from '#tests/support/components/renderComponent.ts'
+import { mockApplicationConfig } from '#tests/support/mock-applicationConfig.ts'
+import { mockGraphQLApi } from '#tests/support/mock-graphql-api.ts'
+
+import { createDummyTicket } from '#shared/entities/ticket-article/__tests__/mocks/ticket.ts'
+import { GraphQLErrorTypes } from '#shared/types/error.ts'
+
+import gitlabPlugin from '#desktop/pages/ticket/components/TicketSidebar/plugins/gitlab.ts'
+import TicketSidebarGitLab from '#desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/TicketSidebarGitLab/TicketSidebarGitLab.vue'
+import { TicketExternalReferencesIssueTrackerItemListDocument } from '#desktop/pages/ticket/graphql/queries/ticketExternalReferencesIssueTrackerList.api.ts'
+import { TicketSidebarScreenType } from '#desktop/pages/ticket/types/sidebar.ts'
+
+describe('errors', () => {
+  it('shows an generic error message if query fails due failure of GitLab api', async () => {
+    mockApplicationConfig({
+      gitlab_integration: true,
+    })
+    mockGraphQLApi(
+      TicketExternalReferencesIssueTrackerItemListDocument,
+    ).willFailWithError([
+      {
+        message:
+          'GitLab request failed. Please have a look at the log file for details',
+        extensions: {
+          type: GraphQLErrorTypes.UnknownError,
+        },
+      },
+    ])
+
+    const wrapper = renderComponent(TicketSidebarGitLab, {
+      props: {
+        sidebar: 'gitlab',
+        sidebarPlugin: gitlabPlugin,
+        selected: true,
+        context: {
+          screenType: TicketSidebarScreenType.TicketDetailView,
+          formValues: {},
+          toggleCollapse: () => {},
+          isCollapsed: false,
+          ticket: computed(() =>
+            createDummyTicket({
+              externalReferences: {
+                gitlab: [
+                  // 'https://git.zammad.com/zammad/zammad/-/issues/123',
+                  // 'https://git.zammad.com/zammad/zammad/-/issues/124',
+                ],
+              },
+            }),
+          ),
+          isTicketEditable: true,
+        },
+      },
+      global: {
+        stubs: {
+          teleport: true,
+        },
+      },
+      flyout: true,
+      form: true,
+      router: true,
+      store: true,
+    })
+
+    expect(await wrapper.findByRole('alert')).toHaveTextContent(
+      'Error fetching information from GitLab. Please contact your administrator.',
+    )
+
+    expect(
+      wrapper.queryByRole('button', { name: 'Action menu button' }),
+    ).not.toBeInTheDocument()
+  })
+})

+ 9 - 2
app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarExternalIssueTracker/useTicketExternalIssueTracker.ts

@@ -4,6 +4,7 @@ import { isEqual } from 'lodash-es'
 import { computed, ref, type Ref, watch } from 'vue'
 
 import { EnumTicketExternalReferencesIssueTrackerType } from '#shared/graphql/types.ts'
+import { i18n } from '#shared/i18n.ts'
 import { QueryHandler } from '#shared/server/apollo/handler/index.ts'
 
 import { useTicketExternalReferencesIssueTrackerItemListQuery } from '#desktop/pages/ticket/graphql/queries/ticketExternalReferencesIssueTrackerList.api.ts'
@@ -46,10 +47,16 @@ export const useTicketExternalIssueTracker = (
 
   const queryError = issueTrackerQuery.operationError()
 
+  const trackerTypeTranslationMap = {
+    [EnumTicketExternalReferencesIssueTrackerType.Github]: __('GitHub'),
+    [EnumTicketExternalReferencesIssueTrackerType.Gitlab]: __('GitLab'),
+  }
+
   const error = computed(() =>
     queryError.value
-      ? __(
-          'Error fetching github information. Please contact your administrator.',
+      ? i18n.t(
+          `Error fetching information from %s. Please contact your administrator.`,
+          trackerTypeTranslationMap[issueTrackerType],
         )
       : null,
   )

+ 15 - 2
app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarIdoit/TicketSidebarIdoitContent.vue

@@ -60,12 +60,25 @@ const objectListQuery = new QueryHandler(
           : 'cache-and-network',
     }),
   ),
+  {
+    errorShowNotification: false,
+  },
 )
 
 const result = objectListQuery.result()
 
 const isLoading = objectListQuery.loading()
 
+const queryError = objectListQuery.operationError()
+
+const error = computed(() =>
+  queryError.value
+    ? __(
+        `Error fetching information from i-doit. Please contact your administrator.`,
+      )
+    : null,
+)
+
 const objectList = computed(() => {
   return result.value?.ticketExternalReferencesIdoitObjectList || []
 })
@@ -130,7 +143,7 @@ const openFlyout = () =>
   })
 
 const actions = computed((): MenuItem[] =>
-  props.objectIds?.length
+  props.objectIds?.length && !error.value
     ? [
         {
           key: 'link-idoit-object',
@@ -180,7 +193,7 @@ if (props.ticketId) {
       {{ $t('Link Objects') }}
     </CommonButton>
 
-    <CommonLoader v-if="objectIds?.length" :loading="isLoading">
+    <CommonLoader v-if="objectIds?.length" :loading="isLoading" :error="error">
       <div class="space-y-6" tabindex="-1">
         <div
           v-for="object in objectList"

+ 11 - 5
app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarIdoit/__tests__/TicketSidebarIdoit.spec.ts

@@ -43,14 +43,20 @@ const mockedData = [
   },
 ]
 
-const renderIdoitSidebar = (isTicketEditable = true, objects = mockedData) => {
+const renderIdoitSidebar = (
+  isTicketEditable = true,
+  objects = mockedData,
+  customMocks = false,
+) => {
   mockApplicationConfig({
     idoit_integration: true,
   })
 
-  mockTicketExternalReferencesIdoitObjectListQuery({
-    ticketExternalReferencesIdoitObjectList: objects,
-  })
+  if (!customMocks) {
+    mockTicketExternalReferencesIdoitObjectListQuery({
+      ticketExternalReferencesIdoitObjectList: objects,
+    })
+  }
 
   const iDoitIds: number[] = []
 
@@ -65,7 +71,7 @@ const renderIdoitSidebar = (isTicketEditable = true, objects = mockedData) => {
 
   return renderComponent(TicketSidebarIdoit, {
     props: {
-      sidebar: 'github',
+      sidebar: 'i-doit',
       sidebarPlugin: idoitPlugin,
       selected: true,
       context: {

+ 97 - 0
app/frontend/apps/desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarIdoit/__tests__/TicketSidebarIdoitError.spec.ts

@@ -0,0 +1,97 @@
+// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
+
+import { ref } from 'vue'
+
+import renderComponent from '#tests/support/components/renderComponent.ts'
+import { mockApplicationConfig } from '#tests/support/mock-applicationConfig.ts'
+import { mockGraphQLApi } from '#tests/support/mock-graphql-api.ts'
+
+import { createDummyTicket } from '#shared/entities/ticket-article/__tests__/mocks/ticket.ts'
+import { GraphQLErrorTypes } from '#shared/types/error.ts'
+
+import idoitPlugin from '#desktop/pages/ticket/components/TicketSidebar/plugins/idoit.ts'
+import TicketSidebarIdoit from '#desktop/pages/ticket/components/TicketSidebar/TicketSidebarExternalReferences/TicketSidebarIdoit/TicketSidebarIdoit.vue'
+import { TicketExternalReferencesIdoitObjectListDocument } from '#desktop/pages/ticket/graphql/queries/ticketExternalReferencesIdoitObjectList.api.ts'
+import { TicketSidebarScreenType } from '#desktop/pages/ticket/types/sidebar.ts'
+
+vi.mock('#shared/server/apollo/client.ts', () => ({
+  getApolloClient: () => ({
+    cache: {
+      readQuery: vi.fn(),
+      writeQuery: vi.fn(),
+    },
+  }),
+}))
+
+describe('errors', () => {
+  it('shows an generic error message if query fails due failure of i-doit api', async () => {
+    mockApplicationConfig({
+      idoit_integration: true,
+    })
+    mockGraphQLApi(
+      TicketExternalReferencesIdoitObjectListDocument,
+    ).willFailWithError([
+      {
+        message:
+          'I-doit request failed. Please have a look at the log file for details',
+        extensions: {
+          type: GraphQLErrorTypes.UnknownError,
+        },
+      },
+    ])
+
+    const wrapper = renderComponent(TicketSidebarIdoit, {
+      props: {
+        sidebar: 'i-doit',
+        sidebarPlugin: idoitPlugin,
+        selected: true,
+        context: {
+          screenType: TicketSidebarScreenType.TicketDetailView,
+          formValues: {},
+          toggleCollapse: () => {},
+          isCollapsed: false,
+          ticket: ref(
+            createDummyTicket({
+              preferences: {
+                idoit: {
+                  object_ids: [
+                    {
+                      idoitObjectId: 111,
+                      title: 'Object 1',
+                      link: 'www.idoit.com/?object_id=111',
+                      type: 'Application',
+                    },
+                    {
+                      idoitObjectId: 2222,
+                      title: 'Object 2',
+                      link: 'www.idoit.com/?object_id=222',
+                      type: 'Monitor',
+                    },
+                  ],
+                },
+              },
+            }),
+          ),
+          isTicketEditable: true,
+        },
+      },
+      global: {
+        stubs: {
+          teleport: true,
+        },
+      },
+      flyout: true,
+      form: true,
+      router: true,
+      store: true,
+    })
+
+    expect(await wrapper.findByRole('alert')).toHaveTextContent(
+      'Error fetching information from i-doit. Please contact your administrator.',
+    )
+
+    expect(
+      wrapper.queryByRole('button', { name: 'Action menu button' }),
+    ).not.toBeInTheDocument()
+  })
+})

Некоторые файлы не были показаны из-за большого количества измененных файлов