Browse Source

Maintenance: Desktop view - Click on checklist badge in ticket top bar does...

Benjamin Scharf 2 months ago
parent
commit
99c53489d8

+ 1 - 1
app/frontend/apps/desktop/components/CollapseButton/__tests__/useCollapseHandler.spec.ts

@@ -4,7 +4,7 @@ import { mount } from '@vue/test-utils'
 import { beforeEach, vi } from 'vitest'
 import { nextTick } from 'vue'
 
-import { useCollapseHandler } from '#desktop/components/CollapseButton/composables/useCollapseHandler.ts'
+import { useCollapseHandler } from '#desktop/components/CollapseButton/useCollapseHandler.ts'
 
 describe('useCollapseHandler', async () => {
   const emit = vi.fn()

+ 11 - 0
app/frontend/apps/desktop/components/CollapseButton/types.ts

@@ -0,0 +1,11 @@
+// Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
+
+export interface CollapseOptions {
+  storageKey?: string
+  name?: string
+}
+
+export interface CollapseEmit {
+  (event: 'collapse', arg: boolean): void
+  (event: 'expand', arg: boolean): void
+}

+ 15 - 19
app/frontend/apps/desktop/components/CollapseButton/composables/useCollapseHandler.ts → app/frontend/apps/desktop/components/CollapseButton/useCollapseHandler.ts

@@ -3,18 +3,17 @@
 import { useLocalStorage } from '@vueuse/core'
 import { onMounted, type Ref, ref, watch } from 'vue'
 
-interface Emits {
-  (event: 'collapse', arg: boolean): void
-  (event: 'expand', arg: boolean): void
-}
+import emitter from '#shared/utils/emitter.ts'
+
+import type { CollapseOptions, CollapseEmit } from './types.ts'
 
 /**
  * @args emit - The emit function from the setup function
  * @args options.storageKey - The key to store the collapse state in local storage
  * * */
 export const useCollapseHandler = (
-  emit: Emits,
-  options?: { storageKey?: string },
+  emit: CollapseEmit,
+  options?: CollapseOptions,
 ) => {
   let isCollapsed: Ref<boolean>
 
@@ -24,29 +23,26 @@ export const useCollapseHandler = (
     isCollapsed = ref(false)
   }
 
+  const callEmit = () =>
+    isCollapsed.value ? emit('collapse', true) : emit('expand', true)
+
   const toggleCollapse = () => {
     isCollapsed.value = !isCollapsed.value
 
-    if (isCollapsed.value) {
-      emit('collapse', true)
-      return
-    }
-
-    emit('expand', true)
+    callEmit()
   }
 
+  emitter.on('expand-collapsed-content', (name: string) => {
+    if (options?.name === name && isCollapsed.value) toggleCollapse()
+  })
+
   onMounted(() => {
     // Set up watcher on the local storage value, so other browser tabs can sync their collapse states.
     if (options?.storageKey) {
       watch(
         isCollapsed,
-        (newValue) => {
-          if (newValue) {
-            emit('collapse', true)
-            return
-          }
-
-          emit('expand', true)
+        () => {
+          callEmit()
         },
         {
           immediate: true,

+ 1 - 1
app/frontend/apps/desktop/components/CommonSectionCollapse/CommonSectionCollapse.vue

@@ -4,7 +4,7 @@
 import { computed, watch } from 'vue'
 
 import CollapseButton from '#desktop/components/CollapseButton/CollapseButton.vue'
-import { useCollapseHandler } from '#desktop/components/CollapseButton/composables/useCollapseHandler.ts'
+import { useCollapseHandler } from '#desktop/components/CollapseButton/useCollapseHandler.ts'
 import { useTransitionCollapse } from '#desktop/composables/useTransitionCollapse.ts'
 
 export interface Props {

+ 5 - 2
app/frontend/apps/desktop/components/layout/LayoutSidebar.vue

@@ -5,7 +5,8 @@ import { useActiveElement } from '@vueuse/core'
 import { computed, useTemplateRef, watch } from 'vue'
 
 import CollapseButton from '#desktop/components/CollapseButton/CollapseButton.vue'
-import { useCollapseHandler } from '#desktop/components/CollapseButton/composables/useCollapseHandler.ts'
+import type { CollapseOptions } from '#desktop/components/CollapseButton/types.ts'
+import { useCollapseHandler } from '#desktop/components/CollapseButton/useCollapseHandler.ts'
 import CommonButton from '#desktop/components/CommonButton/CommonButton.vue'
 import ResizeLine from '#desktop/components/ResizeLine/ResizeLine.vue'
 import { useResizeLine } from '#desktop/components/ResizeLine/useResizeLine.ts'
@@ -51,7 +52,9 @@ const emit = defineEmits<{
   expand: [boolean]
 }>()
 
-const collapseOptions: { storageKey?: string } = {}
+const collapseOptions: CollapseOptions = {
+  name: props.name,
+}
 
 if (props.rememberCollapse)
   collapseOptions.storageKey = `${props.name}-sidebar-collapsed`

+ 0 - 16
app/frontend/apps/desktop/components/layout/composables/useMainLayoutContainer.ts

@@ -1,16 +0,0 @@
-// Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/
-
-import { type ComputedRef, type InjectionKey, inject } from 'vue'
-
-/*
- * Injection key for the main content container in LayoutMain
- * */
-export const MAIN_LAYOUT_KEY = Symbol('main-content-container') as InjectionKey<
-  ComputedRef<HTMLElement | undefined>
->
-
-export const useMainLayoutContainer = () => {
-  return {
-    node: inject(MAIN_LAYOUT_KEY),
-  }
-}

+ 32 - 0
app/frontend/apps/desktop/pages/ticket/__tests__/ticket-detail-view/ticket-detail-view-checklists.spec.ts

@@ -451,4 +451,36 @@ describe('Ticket detail view', () => {
       )
     })
   })
+
+  it('displays the checklist sidebar when it was previously collapsed and another right sidebar tab was active.', async () => {
+    mockApplicationConfig({ checklist: true })
+
+    mockTicketQuery({
+      ticket: createDummyTicket({
+        checklist: {
+          id: convertToGraphQLId('Checklist', 5),
+          completed: false,
+          incomplete: 3,
+          total: 4,
+          complete: 1,
+        },
+      }),
+    })
+
+    const view = await visitView('/tickets/1')
+
+    await view.events.click(view.getByRole('button', { name: 'Ticket' }))
+
+    expect(
+      view.getByRole('heading', { name: 'Ticket', level: 2 }),
+    ).toBeInTheDocument()
+
+    await view.events.click(
+      view.getByRole('button', { name: 'Open Checklist' }),
+    )
+
+    expect(
+      await view.findByRole('heading', { name: 'Checklist', level: 2 }),
+    ).toBeInTheDocument()
+  })
 })

+ 6 - 0
app/frontend/apps/desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TopBarHeader/TicketInformation/TicketInformationBadgeList/ChecklistBadgeList.vue

@@ -3,6 +3,9 @@
 <script setup lang="ts">
 import { computed } from 'vue'
 
+import { useSessionStore } from '#shared/stores/session.ts'
+import emitter from '#shared/utils/emitter.ts'
+
 import ChecklistBadge from '#desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TopBarHeader/TicketInformation/TicketInformationBadgeList/ChecklistBadge.vue'
 import ReferencingTicketsBadgePopover from '#desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TopBarHeader/TicketInformation/TicketInformationBadgeList/ReferencingTicketsBadgePopover.vue'
 import type { ReferencingTicket } from '#desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TopBarHeader/TicketInformation/TicketInformationBadgeList/types.ts'
@@ -24,8 +27,11 @@ const totalItemsCount = computed(() => checklist.value?.total)
 
 const isCompleted = computed(() => checklist.value?.completed)
 
+const { userId } = useSessionStore()
+
 const openChecklistInSidebar = () => {
   ticketSidebar.switchSidebar('checklist')
+  emitter.emit('expand-collapsed-content', `${userId}-ticket-detail`)
 }
 </script>
 

+ 1 - 0
app/frontend/shared/utils/emitter.ts

@@ -4,6 +4,7 @@ import mitt, { type Emitter } from 'mitt'
 
 type Events = {
   sessionInvalid: void
+  'expand-collapsed-content': string
 }
 
 const emitter: Emitter<Events> = mitt<Events>()

+ 6 - 6
i18n/zammad.pot

@@ -300,7 +300,7 @@ msgstr ""
 
 #: app/assets/javascripts/app/views/ticket_zoom/meta.jst.eco:19
 #: app/frontend/apps/desktop/pages/guided-setup/views/GuidedSetupImport/GuidedSetupImportSource/GuidedSetupImportSourceStatus.vue:234
-#: app/frontend/apps/desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TopBarHeader/TicketInformation/TicketInformationBadgeList/ChecklistBadgeList.vue:48
+#: app/frontend/apps/desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TopBarHeader/TicketInformation/TicketInformationBadgeList/ChecklistBadgeList.vue:54
 msgid "%s of %s"
 msgstr ""
 
@@ -2991,7 +2991,7 @@ msgstr ""
 msgid "Closing time"
 msgstr ""
 
-#: app/frontend/apps/desktop/components/layout/LayoutSidebar.vue:175
+#: app/frontend/apps/desktop/components/layout/LayoutSidebar.vue:178
 msgid "Collapse sidebar"
 msgstr ""
 
@@ -6097,7 +6097,7 @@ msgstr ""
 msgid "Existing tickets (open)"
 msgstr ""
 
-#: app/frontend/apps/desktop/components/layout/LayoutSidebar.vue:176
+#: app/frontend/apps/desktop/components/layout/LayoutSidebar.vue:179
 msgid "Expand sidebar"
 msgstr ""
 
@@ -10486,7 +10486,7 @@ msgstr ""
 msgid "Open %s"
 msgstr ""
 
-#: app/frontend/apps/desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TopBarHeader/TicketInformation/TicketInformationBadgeList/ChecklistBadgeList.vue:35
+#: app/frontend/apps/desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TopBarHeader/TicketInformation/TicketInformationBadgeList/ChecklistBadgeList.vue:41
 msgid "Open Checklist"
 msgstr ""
 
@@ -12071,7 +12071,7 @@ msgstr ""
 msgid "Resize side panel"
 msgstr ""
 
-#: app/frontend/apps/desktop/components/layout/LayoutSidebar.vue:145
+#: app/frontend/apps/desktop/components/layout/LayoutSidebar.vue:148
 msgid "Resize sidebar"
 msgstr ""
 
@@ -18328,7 +18328,7 @@ msgstr ""
 msgid "chat"
 msgstr ""
 
-#: app/frontend/apps/desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TopBarHeader/TicketInformation/TicketInformationBadgeList/ChecklistBadgeList.vue:44
+#: app/frontend/apps/desktop/pages/ticket/components/TicketDetailView/TicketDetailTopBar/TopBarHeader/TicketInformation/TicketInformationBadgeList/ChecklistBadgeList.vue:50
 msgid "checked"
 msgstr ""