Maintenance: Desktop view - Popover instance is bound to wrong owner

This commit is contained in:
Benjamin Scharf
2025-12-08 15:42:42 +01:00
parent d224546f25
commit db91c5e3eb
4 changed files with 17 additions and 16 deletions

View File

@@ -1,7 +1,7 @@
<!-- Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/ -->
<script setup lang="ts">
import { computed, type SetupContext, toRefs, useSlots } from 'vue'
import { computed, toRefs, useSlots } from 'vue'
import type { ObjectLike } from '#shared/types/utils.ts'
@@ -27,14 +27,13 @@ const emit = defineEmits<{
const { items, entity } = toRefs(props)
const { filteredMenuItems } = usePopoverMenu(items, entity)
// If no explicit items prop is provided, inject from a parent provider (e.g., CommonActionMenu)
// Otherwise, create an independent instance for this component
const { filteredMenuItems } = usePopoverMenu(items, entity, {
injects: !items.value?.length,
})
/**
* Workaround to satisfy linter
* @bug https://github.com/vuejs/language-tools/issues/5082
* Wait to be closed
* */
const slots: SetupContext['slots'] = useSlots()
const slots = useSlots()
const showHeaderLabel = computed(() => {
if (!filteredMenuItems.value && !slots.default) return false

View File

@@ -14,13 +14,13 @@ const POPOVER_MENU_SYMBOL = Symbol('popover-menu')
export const usePopoverMenu = (
items: Ref<MenuItem[] | undefined>,
entity: Ref<ObjectLike | undefined>,
options: { provides?: boolean } = {},
options: { provides?: boolean; injects?: boolean } = {},
) => {
const { provides = false, injects = false } = options
const injectPopoverMenu = inject<Maybe<UsePopoverMenuReturn>>(POPOVER_MENU_SYMBOL, null)
if (injectPopoverMenu) return injectPopoverMenu
const { provides = false } = options
if (injects && injectPopoverMenu) return injectPopoverMenu
const session = useSessionStore()

View File

@@ -32,9 +32,11 @@ interface Props {
const props = withDefaults(defineProps<Props>(), {
visible: true,
targetId: getUuid(),
})
// Generate unique targetId per component instance to avoid cross-editor targeting
const targetId = computed(() => props.targetId || `editor-action-menu-${getUuid()}`)
const emit = defineEmits<{
hide: []
blur: []
@@ -114,7 +116,7 @@ onKeyUp(['ArrowDown', 'ArrowUp', 'ArrowLeft', 'ArrowRight'], (e) => {
useEventListener('click', (e) => {
const target = e.target as HTMLDivElement
const targetElementWithId = target.closest(`#${CSS.escape(props.targetId)}`)
const targetElementWithId = target.closest(`#${CSS.escape(targetId.value)}`)
if (targetElementWithId) {
setPopoverTarget(targetElementWithId as HTMLDivElement)
@@ -126,7 +128,7 @@ useEventListener('click', (e) => {
const handleMenuItemClick = (action: MenuItem, event: MouseEvent) => {
if ((action as ActionItem).subMenu) {
const newPopoverTarget = document.getElementById(`${CSS.escape(props.targetId)}`)
const newPopoverTarget = document.getElementById(`${CSS.escape(targetId.value)}`)
if (newPopoverTarget) {
popoverTarget.value = newPopoverTarget as HTMLDivElement
}

View File

@@ -10852,7 +10852,7 @@ msgstr ""
msgid "No import in progress."
msgstr ""
#: app/frontend/apps/desktop/components/CommonPopoverMenu/CommonPopoverMenu.vue:160
#: app/frontend/apps/desktop/components/CommonPopoverMenu/CommonPopoverMenu.vue:159
msgid "No items available"
msgstr ""