diff --git a/shell/components/nav/NotificationCenter/Notification.vue b/shell/components/nav/NotificationCenter/Notification.vue index cabdded3cb..3b32bad931 100644 --- a/shell/components/nav/NotificationCenter/Notification.vue +++ b/shell/components/nav/NotificationCenter/Notification.vue @@ -4,10 +4,11 @@ import { DATE_FORMAT, TIME_FORMAT } from '@shell/store/prefs'; import { escapeHtml } from '@shell/utils/string'; import { computed, inject, ref } from 'vue'; import { useStore } from 'vuex'; +import { useRouter } from 'vue-router'; import { useI18n } from '@shell/composables/useI18n'; -import { NotificationAction, NotificationLevel } from '@shell/types/notifications'; -import { StoredNotification } from '@shell/store/notifications'; +import { NotificationAction, NotificationLevel, StoredNotification } from '@shell/types/notifications'; import { DropdownContext, defaultContext } from '@components/RcDropdown/types'; +import { useDropdownItem } from '@components/RcDropdown/useDropdownItem'; const CLASSES = { [NotificationLevel.Announcement]: 'icon-notify-announcement text-info', @@ -25,10 +26,13 @@ const { dropdownItems } = inject('dropdownContext') || defaultC const store = useStore(); const { t } = useI18n(store); +const router = useRouter(); const unreadCount = computed(() => store.getters['notifications/unreadCount']); const dateFormat = escapeHtml( store.getters['prefs/get'](DATE_FORMAT)); const timeFormat = escapeHtml( store.getters['prefs/get'](TIME_FORMAT)); +const { close, scrollIntoView } = useDropdownItem(); + // Outer element for the notification const dropdownMenuItem = ref(); @@ -77,9 +81,21 @@ const age = computed(() => { const clz = computed(() => CLASSES[props.item.level]); -// Open a URL from either the primary or secondary buttons in a new tab +// Invoke action on either the primary or secondary buttons +// This can open a URL in a new tab OR navigate to an application route const action = (action: NotificationAction) => { - window.open(action.target, '_blank'); + if (action.target) { + window.open(action.target, '_blank'); + } else if (action.route) { + try { + router.push(action.route); + } catch (e) { + console.error('Error navigating to route for the notification action', e); // eslint-disable-line no-console + } + close(); + } else { + console.error('Notification action must either specify a "target" or a "route"'); // eslint-disable-line no-console + } }; const toggleRead = (e: MouseEvent | KeyboardEvent, fromKeyboard = false) => { @@ -166,6 +182,14 @@ const handleKeydown = (e: KeyboardEvent) => { } }; +/** + * This allows the user to press up/down while in the focus trap for a notification and exit the focus trap and move to the next/previous notification + */ +const handleKeydownFocusTrap = (e: KeyboardEvent) => { + exitFocusTrap(e); + handleKeydown(e); +}; + /** * Finds the new index for the dropdown item based on the key pressed. * @param shouldAdvance - Whether to advance to the next or previous item. @@ -193,22 +217,6 @@ const findNewIndex = (shouldAdvance: boolean, activeIndex: number, itemsArr: Ele return newIndex; }; - -/** - * Ensure we scroll the item into view smoothly - * @param event FocusIn Event - */ -const scrollIntoView = (event: Event) => { - const target = event.target; - - if (target instanceof HTMLElement) { - target?.scrollIntoView({ - behavior: 'smooth', - block: 'center', - inline: 'nearest', - }); - } -};