diff --git a/locales/en/plugin__odf-console.json b/locales/en/plugin__odf-console.json index 60d21cebf..22a71557b 100644 --- a/locales/en/plugin__odf-console.json +++ b/locales/en/plugin__odf-console.json @@ -1159,8 +1159,8 @@ "Edit labels": "Edit labels", "Edit annotations": "Edit annotations", "Edit bucket": "Edit bucket", - "Objects": "Objects", "Refresh": "Refresh", + "Objects": "Objects", "Created via OBC": "Created via OBC", "Created via S3": "Created via S3", "MCG": "MCG", diff --git a/packages/shared/src/kebab/kebab.tsx b/packages/shared/src/kebab/kebab.tsx index ca58525e1..47781affc 100644 --- a/packages/shared/src/kebab/kebab.tsx +++ b/packages/shared/src/kebab/kebab.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { useCallback, useEffect } from 'react'; import { getName, getNamespace } from '@odf/shared/selectors'; import { K8sResourceCommon, @@ -21,6 +22,32 @@ import { ModalKeys, defaultModalMap } from '../modals/types'; import { useCustomTranslation } from '../useCustomTranslationHook'; import { referenceForModel } from '../utils'; +const useClickOutside = ( + ref: React.RefObject, + callback: () => void +) => { + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (ref.current && !ref.current.contains(event.target as Node)) { + callback(); + } + }; + + const handleEscapeKey = (event: KeyboardEvent) => { + if (event.key === 'Escape') { + callback(); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + document.addEventListener('keydown', handleEscapeKey); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + document.removeEventListener('keydown', handleEscapeKey); + }; + }, [ref, callback]); +}; + export type CustomKebabItem = { key: string; value: string; @@ -102,19 +129,19 @@ export const Kebab: React.FC & KebabStaticProperties = ({ hideItems, }) => { const { t } = useCustomTranslation(); - const launchModal = useModal(); - const eventRef = React.useRef(undefined); const dropdownToggleRef = React.useRef(); const [toggleDirection, setToggleDirection] = React.useState('down'); const [isOpen, setOpen] = React.useState(false); + const closeDropdown = useCallback(() => setOpen(false), []); - const { resourceModel, resource } = extraProps; + // Use the custom hook to detect clicks outside the Kebab menu + useClickOutside(dropdownToggleRef, closeDropdown); + const { resourceModel, resource } = extraProps; const resourceLabel = resourceModel.label; - const navigate = useNavigate(); const [canCreate, createLoading] = useAccessReview({ @@ -241,6 +268,7 @@ export const Kebab: React.FC & KebabStaticProperties = ({ const content = _.has(resource.metadata, 'deletionTimestamp') ? terminatingTooltip || t('Resource is being deleted.') : ''; + return ( & KebabStaticProperties = ({ ref={dropdownToggleRef} aria-label="Dropdown toggle" variant={toggleType === 'Kebab' ? 'plain' : 'default'} - onClick={() => setOpen((o) => !o)} + onClick={() => setOpen(!isOpen)} isExpanded={isOpen} data-test="kebab-button" isDisabled={isDisabled}