Revert merge errors

This commit is contained in:
Neil MacDougall 2025-09-05 12:44:32 +01:00
parent ee46dbad08
commit ab7f8e4358
1 changed files with 56 additions and 36 deletions

View File

@ -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>('dropdownContext') || defaultC
const store = useStore();
const { t } = useI18n(store);
const router = useRouter();
const unreadCount = computed<number>(() => 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<HTMLElement>();
@ -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',
});
}
};
</script>
<template>
@ -219,6 +227,7 @@ const scrollIntoView = (event: Event) => {
role="menuitem"
data-testid="notifications-center-item"
:aria-label="t('notificationCenter.ariaLabel', { title: item.title })"
:class="{ 'notification-unread': !item.read }"
@keydown.up.down.stop.prevent="handleKeydown"
@focusin="scrollIntoView"
@focus.stop="gotFocus"
@ -242,18 +251,22 @@ const scrollIntoView = (event: Event) => {
</div>
<button
ref="readButton"
v-clean-tooltip="item.read ? t('notificationCenter.markUnread') : t('notificationCenter.markRead')"
class="read-indicator"
role="button"
:aria-label="toggleLabel"
@keydown.enter.space.stop="toggleRead($event, true)"
@keydown.tab.stop="innerFocusNext($event)"
@keydown.escape.stop="exitFocusTrap"
@keydown.up.down.prevent.stop="handleKeydownFocusTrap"
@click.stop="toggleRead($event, false)"
>
<div
class="read-icon"
:class="{ 'unread': !item.read }"
/>
<div>
<div
class="read-icon"
:class="{ 'unread': !item.read }"
/>
</div>
</button>
</div>
<div class="bottom">
@ -293,7 +306,8 @@ const scrollIntoView = (event: Event) => {
@keydown.enter.space.stop="action(item.primaryAction)"
@keydown.tab.stop="innerFocusNext($event)"
@keydown.escape.stop="exitFocusTrap"
@click.stop="action(item.primaryAction)"
@click.stop.prevent="action(item.primaryAction)"
@keydown.up.down.prevent.stop="handleKeydownFocusTrap"
>
{{ item.primaryAction.label }}
</button>
@ -305,7 +319,8 @@ const scrollIntoView = (event: Event) => {
@keydown.enter.space.stop="action(item.secondaryAction)"
@keydown.tab.stop="innerFocusNext($event)"
@keydown.escape.stop="exitFocusTrap"
@click.stop="action(item.secondaryAction)"
@click.stop.prevent="action(item.secondaryAction)"
@keydown.up.down.prevent.stop="handleKeydownFocusTrap"
>
{{ item.secondaryAction.label }}
</button>
@ -321,8 +336,11 @@ const scrollIntoView = (event: Event) => {
gap: 8px;
align-items: center;
padding: 12px;
margin: 0 8px;
border-radius: 4px;
margin: 0 3px;
&.notification-unread {
background-color: var(--notification-unread-bg);
}
&:focus-visible, &:focus {
@include focus-outline;
@ -337,7 +355,7 @@ const scrollIntoView = (event: Event) => {
.top {
align-items: center;
display: flex;
padding: 4px 0;
padding: 0;
.icon {
display: flex;
@ -357,11 +375,12 @@ const scrollIntoView = (event: Event) => {
button.read-indicator {
line-height: normal;
min-height: auto;
padding: 0;
padding: 8px;
margin-left: 16px;
width: 10px;
height: 10px;
background-color: var(--body-bg);
background-color: unset;
display: flex;
align-items: center;
justify-content: center;
&:disabled {
cursor: default;
@ -375,8 +394,8 @@ const scrollIntoView = (event: Event) => {
.read-icon {
border: 2px solid var(--primary);
border-radius: 50%;
width: 10px;
height: 10px;
width: 8px;
height: 8px;
&.unread {
background-color: var(--primary);
@ -394,10 +413,11 @@ const scrollIntoView = (event: Event) => {
margin-left: 32px; // 20px icon + 12px spacing
.created {
font-size: 12px;
font-size: 13px;
}
.message {
line-height: 20px;
padding: 6px 0;
}